From c5c3f096d8a85b4a9259b24a61867c73ef0cba4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 7 Feb 2025 10:09:06 +0000 Subject: [PATCH] fix: revert "feat: partial note handling in aztec-nr (#11641)" (#11797) #11641 caused some CI failures in tests that are only run under e2e-all, so this went undetected. Reverting the changes to fix master until we address them. --- .../aztec-nr/aztec/src/discovery/mod.nr | 77 ------- .../aztec/src/discovery/nonce_discovery.nr | 94 -------- .../aztec/src/discovery/partial_notes.nr | 153 ------------- .../aztec/src/discovery/private_logs.nr | 193 ---------------- noir-projects/aztec-nr/aztec/src/lib.nr | 1 - .../aztec/src/macros/functions/mod.nr | 53 +---- .../aztec-nr/aztec/src/macros/mod.nr | 213 ++++++++++-------- .../aztec-nr/aztec/src/note/discovery/mod.nr | 130 +++++++++++ noir-projects/aztec-nr/aztec/src/note/mod.nr | 1 + .../aztec-nr/aztec/src/note/note_interface.nr | 4 +- .../aztec-nr/aztec/src/note/utils.nr | 22 +- .../aztec/src/oracle/note_discovery.nr | 30 +-- .../aztec-nr/aztec/src/oracle/notes.nr | 26 ++- .../aztec-nr/aztec/src/utils/array/append.nr | 48 ---- .../aztec-nr/aztec/src/utils/array/mod.nr | 12 - .../aztec-nr/aztec/src/utils/array/subbvec.nr | 4 +- .../contracts/counter_contract/src/main.nr | 9 +- .../crates/types/src/lib.nr | 1 - .../crates/types/src/log_with_tx_data.nr | 14 -- yarn-project/circuits.js/src/structs/index.ts | 1 - .../src/structs/log_with_tx_data.ts | 36 --- .../pxe/src/simulator_oracle/index.ts | 42 +--- .../simulator/src/acvm/deserialize.ts | 2 +- .../simulator/src/acvm/oracle/oracle.ts | 13 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 5 - yarn-project/simulator/src/acvm/serialize.ts | 7 - .../src/client/client_execution_context.ts | 7 - .../simulator/src/client/db_oracle.ts | 9 - .../src/client/private_execution.test.ts | 4 - .../client/unconstrained_execution.test.ts | 5 +- .../simulator/src/client/view_data_oracle.ts | 5 - yarn-project/txe/src/oracle/txe_oracle.ts | 5 - 32 files changed, 290 insertions(+), 936 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/discovery/mod.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/discovery/nonce_discovery.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr create mode 100644 noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/utils/array/append.nr delete mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/log_with_tx_data.nr delete mode 100644 yarn-project/circuits.js/src/structs/log_with_tx_data.ts diff --git a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr b/noir-projects/aztec-nr/aztec/src/discovery/mod.nr deleted file mode 100644 index 0988d95ead0..00000000000 --- a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr +++ /dev/null @@ -1,77 +0,0 @@ -use dep::protocol_types::{ - address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_FIELDS, debug_log::debug_log, -}; - -pub mod private_logs; -pub mod partial_notes; -pub mod nonce_discovery; - -/// We reserve two fields in the note private log that are not part of the note content: one for the storage slot, and -/// one for the combined log and note type ID. -global NOTE_PRIVATE_LOG_RESERVED_FIELDS: u32 = 2; - -/// The maximum length of the packed representation of a note's contents. This is limited by private log size and extra -/// fields in the log (e.g. the combined log and note type ID). -// TODO (#11634): we're assuming here that the entire log is plaintext, which is not true due to headers, encryption -// padding, etc. Notes can't actually be this large. -pub global MAX_NOTE_PACKED_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - NOTE_PRIVATE_LOG_RESERVED_FIELDS; - -pub struct NoteHashAndNullifier { - /// The result of NoteInterface::compute_note_hash - pub note_hash: Field, - /// The result of NullifiableNote::compute_nullifier_without_context - pub inner_nullifier: Field, -} - -/// A function which takes a note's packed content, address of the emitting contract, nonce, storage slot and note type -/// ID and attempts to compute its note hash (not siloed by nonce nor address) and inner nullifier (not siloed by -/// address). -/// -/// This function must be user-provided as its implementation requires knowledge of how note type IDs are allocated in a -/// contract. A typical implementation would look like this: -/// -/// ``` -/// |packed_note_content, contract_address, nonce, storage_slot, note_type_id| { -/// if note_type_id == MyNoteType::get_note_type_id() { -/// assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); -/// let hashes = dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( -/// MyNoteType::unpack_content, -/// note_header, -/// true, -/// packed_note_content.storage(), -/// ) -/// -/// Option::some(dep::aztec::oracle::management::NoteHashesAndNullifier { -/// note_hash: hashes[0], -/// inner_nullifier: hashes[3], -/// }) -/// } else if note_type_id == MyOtherNoteType::get_note_type_id() { -/// ... // Similar to above but calling MyOtherNoteType::unpack_content -/// } else { -/// Option::none() // Unknown note type ID -/// }; -/// } -/// ``` -type ComputeNoteHashAndNullifier = fn[Env](/* packed_note_content */BoundedVec, /* contract_address */ AztecAddress, /* nonce */ Field, /* storage_slot */ Field, /* note_type_id */ Field) -> Option; - -/// Performs the note discovery process, in which private and public logs are downloaded and inspected to find private -/// notes, partial notes, and their completion. This is the mechanism via which PXE learns of new notes. -/// -/// Receives the address of the contract on which discovery is performed (i.e. the contract that emitted the notes) -/// along with its `compute_note_hash_and_nullifier` function. -pub unconstrained fn discover_new_notes( - contract_address: AztecAddress, - compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, -) { - debug_log("Performing note discovery"); - - private_logs::fetch_and_process_private_tagged_logs( - contract_address, - compute_note_hash_and_nullifier, - ); - - partial_notes::fetch_and_process_public_partial_note_completion_logs( - contract_address, - compute_note_hash_and_nullifier, - ); -} diff --git a/noir-projects/aztec-nr/aztec/src/discovery/nonce_discovery.nr b/noir-projects/aztec-nr/aztec/src/discovery/nonce_discovery.nr deleted file mode 100644 index a96985796bc..00000000000 --- a/noir-projects/aztec-nr/aztec/src/discovery/nonce_discovery.nr +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{discovery::{MAX_NOTE_PACKED_LEN, NoteHashAndNullifier}, utils::array}; - -use dep::protocol_types::{ - address::AztecAddress, - constants::MAX_NOTE_HASHES_PER_TX, - debug_log::debug_log_format, - hash::{compute_note_hash_nonce, compute_siloed_note_hash, compute_unique_note_hash}, - traits::ToField, -}; - -/// A struct with the discovered information of a complete note, required for delivery to PXE. Note that this is *not* -/// the complete note information, since it does not include content, storage slot, etc. -pub struct DiscoveredNoteInfo { - pub nonce: Field, - pub note_hash: Field, - pub inner_nullifier: Field, -} - -/// Searches for note nonces that will result in a note that was emitted in a transaction. While rare, it is possible -/// for multiple notes to have the exact same packed content and storage slot but different nonces, resulting in -/// different unique note hashes. Because of this this function returns a *vector* of discovered notes, though in most -/// cases it will contain a single element. -/// -/// Due to how nonces are computed, this function requires knowledge of the transaction in which the note was created, -/// more specifically the list of all unique note hashes in it plus the value of its first nullifier. -pub unconstrained fn attempt_note_nonce_discovery( - unique_note_hashes_in_tx: BoundedVec, - first_nullifier_in_tx: Field, - compute_note_hash_and_nullifier: fn[Env](BoundedVec, AztecAddress, Field, Field, Field) -> Option, - contract_address: AztecAddress, - storage_slot: Field, - note_type_id: Field, - packed_note_content: BoundedVec, -) -> BoundedVec { - let discovered_notes = &mut BoundedVec::new(); - - debug_log_format( - "Attempting note discovery on {0} potential notes on contract {1} for storage slot {2}", - [unique_note_hashes_in_tx.len() as Field, contract_address.to_field(), storage_slot], - ); - - // We need to find nonces (typically just one) that result in a note hash that, once siloed into a unique note hash, - // is one of the note hashes created by the transaction. - array::for_each_in_bounded_vec( - unique_note_hashes_in_tx, - |expected_unique_note_hash, i| { - // Nonces are computed by hashing the first nullifier in the transaction with the index of the note in the - // new note hashes array. We therefore know for each note in every transaction what its nonce is. - let candidate_nonce = compute_note_hash_nonce(first_nullifier_in_tx, i); - - // Given nonce, note content and metadata, we can compute the note hash and silo it to check if it matches - // the note hash at the array index we're currently processing. - // TODO(#11157): handle failed note_hash_and_nullifier computation - let hashes = compute_note_hash_and_nullifier( - packed_note_content, - contract_address, - candidate_nonce, - storage_slot, - note_type_id, - ) - .expect(f"Failed to compute a note hash for note type {note_type_id}"); - - let siloed_note_hash = compute_siloed_note_hash(contract_address, hashes.note_hash); - let unique_note_hash = compute_unique_note_hash(candidate_nonce, siloed_note_hash); - - if unique_note_hash == expected_unique_note_hash { - // Note that while we did check that the note hash is the preimage of the expected unique note hash, we - // perform no validations on the nullifier - we fundamentally cannot, since only the application knows - // how to compute nullifiers. We simply trust it to have provided the correct one: if it hasn't, then - // PXE may fail to realize that a given note has been nullified already, and calls to the application - // could result in invalid transactions (with duplicate nullifiers). This is not a concern because an - // application already has more direct means of making a call to it fail the transaction. - discovered_notes.push( - DiscoveredNoteInfo { - nonce: candidate_nonce, - note_hash: hashes.note_hash, - inner_nullifier: hashes.inner_nullifier, - }, - ); - - // We don't exit the loop - it is possible (though rare) for the exact same note content to be present - // multiple times in the same transaction with different nonces. This typically doesn't happen due to - // notes containing random values in order to hide their contents. - } - }, - ); - - debug_log_format( - "Discovered a total of {0} notes", - [discovered_notes.len() as Field], - ); - - *discovered_notes -} diff --git a/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr b/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr deleted file mode 100644 index f8263be8d1f..00000000000 --- a/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr +++ /dev/null @@ -1,153 +0,0 @@ -use crate::{ - discovery::{ - ComputeNoteHashAndNullifier, - nonce_discovery::{attempt_note_nonce_discovery, DiscoveredNoteInfo}, - private_logs::MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN, - }, - oracle::note_discovery::{deliver_note, get_log_by_tag}, - pxe_db::DBArray, - utils::array, -}; - -use dep::protocol_types::{ - address::AztecAddress, - constants::PUBLIC_LOG_DATA_SIZE_IN_FIELDS, - debug_log::debug_log_format, - traits::{Deserialize, Serialize, ToField}, -}; - -/// The slot in the PXE DB where we store a `DBArray` of `DeliveredPendingPartialNote`. -// TODO(#11630): come up with some sort of slot allocation scheme. -pub global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_DB_SLOT: Field = 77; - -/// Public logs contain an extra field at the beginning with the address of the contract that emitted them, and partial -/// notes emit their completion tag in the log, resulting in the first two fields in the public log not being part of -/// the packed public content. -// TODO(#10273): improve how contract log siloing is handled -pub global NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG: u32 = 2; - -/// The maximum length of the packed representation of public fields in a partial note. This is limited by public log -/// size and extra fields in the log (e.g. the tag). -pub global MAX_PUBLIC_PARTIAL_NOTE_PACKED_CONTENT_LENGTH: u32 = - PUBLIC_LOG_DATA_SIZE_IN_FIELDS - NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG; - -/// A partial note that was delivered but is still pending completion. Contains the information necessary to find the -/// log that will complete it and lead to a note being discovered and delivered. -#[derive(Serialize, Deserialize)] -pub(crate) struct DeliveredPendingPartialNote { - pub(crate) note_completion_log_tag: Field, - pub(crate) storage_slot: Field, - pub(crate) note_type_id: Field, - pub(crate) packed_private_note_content: BoundedVec, - pub(crate) recipient: AztecAddress, -} - -/// Searches for public logs that would result in the completion of pending partial notes, ultimately resulting in the -/// notes being delivered to PXE if completed. -pub unconstrained fn fetch_and_process_public_partial_note_completion_logs( - contract_address: AztecAddress, - compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, -) { - let pending_partial_notes = DBArray::at( - contract_address, - DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_DB_SLOT, - ); - - debug_log_format( - "{} pending partial notes", - [pending_partial_notes.len() as Field], - ); - - let mut i = &mut 0; - whyle( - || *i < pending_partial_notes.len(), - || { - let pending_partial_note: DeliveredPendingPartialNote = pending_partial_notes.get(*i); - - let maybe_log = get_log_by_tag(pending_partial_note.note_completion_log_tag); - if maybe_log.is_none() { - debug_log_format( - "Found no completion logs for partial note #{}", - [(*i) as Field], - ); - *i += 1 as u32; - // Note that we're not removing the pending partial note from the PXE DB, so we will continue searching - // for this tagged log when performing note discovery in the future until we either find it or the entry - // is somehow removed from the PXE DB. - } else { - debug_log_format("Completion log found for partial note #{}", [(*i) as Field]); - let log = maybe_log.unwrap(); - - // Public logs have an extra field at the beginning with the contract address, which we use to verify - // that we're getting the logs from the expected contract. - // TODO(#10273): improve how contract log siloing is handled - assert_eq( - log.log_content.get(0), - contract_address.to_field(), - "Got a public log emitted by a different contract", - ); - - // Public fields are assumed to all be placed at the end of the packed representation, so we combine the - // private and public packed fields (i.e. the contents of the log sans the extra fields) to get the - // complete packed content. - let packed_public_note_content: BoundedVec<_, MAX_PUBLIC_PARTIAL_NOTE_PACKED_CONTENT_LENGTH> = - array::subbvec(log.log_content, NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG); - let complete_packed_note_content = array::append( - pending_partial_note.packed_private_note_content, - packed_public_note_content, - ); - - let discovered_notes = attempt_note_nonce_discovery( - log.unique_note_hashes_in_tx, - log.first_nullifier_in_tx, - compute_note_hash_and_nullifier, - contract_address, - pending_partial_note.storage_slot, - pending_partial_note.note_type_id, - complete_packed_note_content, - ); - - debug_log_format( - "Discovered {0} notes for partial note {1}", - [discovered_notes.len() as Field, (*i) as Field], - ); - - array::for_each_in_bounded_vec( - discovered_notes, - |discovered_note: DiscoveredNoteInfo, _| { - // TODO:(#10728): decide how to handle notes that fail delivery. This could be due to e.g. a - // temporary node connectivity issue - is simply throwing good enough here? - assert( - deliver_note( - contract_address, - pending_partial_note.storage_slot, - discovered_note.nonce, - complete_packed_note_content, - discovered_note.note_hash, - discovered_note.inner_nullifier, - log.tx_hash, - pending_partial_note.recipient, - ), - "Failed to deliver note", - ); - }, - ); - - // Because there is only a single log for a given tag, once we've processed the tagged log then we - // simply delete the pending work entry, regardless of whether it was actually completed or not. - // TODO(#11627): only remove the pending entry if we actually process a log that results in the note - // being completed. - pending_partial_notes.remove(*i); - } - }, - ); -} - -/// Custom version of a while loop, calls `body` repeatedly until `condition` returns false. To be removed once Noir -/// supports looping in unconstrained code. -fn whyle(condition: fn[Env]() -> bool, body: fn[Env2]() -> ()) { - if condition() { - body(); - whyle(condition, body); - } -} diff --git a/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr b/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr deleted file mode 100644 index 31f2b32df23..00000000000 --- a/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr +++ /dev/null @@ -1,193 +0,0 @@ -use std::static_assert; - -use crate::{oracle::note_discovery::{deliver_note, sync_notes}, pxe_db::DBArray, utils::array}; - -use dep::protocol_types::{ - address::AztecAddress, - constants::{MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS}, - debug_log::{debug_log, debug_log_format}, -}; - -use crate::discovery::{ - ComputeNoteHashAndNullifier, - MAX_NOTE_PACKED_LEN, - nonce_discovery::{attempt_note_nonce_discovery, DiscoveredNoteInfo}, - NOTE_PRIVATE_LOG_RESERVED_FIELDS, - partial_notes::{ - DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_DB_SLOT, DeliveredPendingPartialNote, - }, -}; - -pub global PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN: u32 = 1; -/// Partial notes have a maximum packed length of their private fields bound by extra content in their private log (i.e. -/// the note completion log tag). -pub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 = - MAX_NOTE_PACKED_LEN - PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN; - -/// Searches for private logs that signal new private notes that are then delivered to PXE, or new partial notes that -/// are stored in the PXE DB so that `fetch_and_process_public_partial_note_completion_logs` can later search for public -/// logs that will complete them. -pub unconstrained fn fetch_and_process_private_tagged_logs( - _contract_address: AztecAddress, - _compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, -) { - // We will eventually fetch tagged logs, decrypt and process them here, but for now we simply call the `syncNotes` - // oracle. This has PXE perform tag synchronization, log download, decryption, and finally calls to the the - // `process_log` contract function with the decrypted payload, which will in turn call `do_process_log` with a - // decrypted log, letting us continue the work outside of PXE. - sync_notes(); -} - -/// Processes a log's plaintext, searching for private notes or partial notes. Private notes result in nonce discovery -/// being performed prior to delivery, which requires knowledge of the transaction hash in which the notes would've been -/// created (typically the same transaction in which the log was emitted), along with the list of unique note hashes in -/// said transaction and the `compute_note_hash_and_nullifier` function. -pub unconstrained fn do_process_log( - contract_address: AztecAddress, - log_plaintext: BoundedVec, - tx_hash: Field, - unique_note_hashes_in_tx: BoundedVec, - first_nullifier_in_tx: Field, - recipient: AztecAddress, - compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, -) { - // The first thing to do is to determine what type of private log we're processing. We currently just have two log - // types: 0 for private notes and 1 for partial notes. This will likely be expanded and improved upon in the future - // to also handle events, etc. - - let (storage_slot, note_type_id, log_type_id, log_payload) = - destructure_log_plaintext(log_plaintext); - - if log_type_id == 0 { - debug_log("Processing private note log"); - - process_private_note_log( - contract_address, - tx_hash, - unique_note_hashes_in_tx, - first_nullifier_in_tx, - recipient, - compute_note_hash_and_nullifier, - storage_slot, - note_type_id, - log_payload, - ); - } else if log_type_id == 1 { - debug_log("Processing partial note private log"); - - process_partial_note_private_log( - contract_address, - storage_slot, - note_type_id, - log_payload, - recipient, - ); - } else { - panic(f"Unknown log type id {log_type_id}"); - } -} - -unconstrained fn destructure_log_plaintext( - log_plaintext: BoundedVec, -) -> (Field, Field, Field, BoundedVec) { - assert(log_plaintext.len() >= NOTE_PRIVATE_LOG_RESERVED_FIELDS); - - // If NOTE_PRIVATE_LOG_RESERVED_FIELDS is changed, causing the assertion below to fail, then the declarations for - // `storage_slot` and `note_type_id` must be updated as well. - static_assert( - NOTE_PRIVATE_LOG_RESERVED_FIELDS == 2, - "unexpected value for NOTE_PRIVATE_LOG_RESERVED_FIELDS", - ); - let storage_slot = log_plaintext.get(0); - - // We currently identify log types by packing the log type ID and note type ID into a single field, called the - // combined type ID. We can do this because the note type ID is only 7 bits long, and so use an 8th bit to - // distinguish private note logs and partial note logs. - // This abuses the fact that the encoding of both of these logs is extremely similar, and will need improving and - // more formalization once we introduce other disimilar log types, such as events. Ideally we'd be able to leverage - // enums and tagged unions to achieve this goal. - let combined_type_id = log_plaintext.get(1); - let note_type_id = ((combined_type_id as u64) % 128) as Field; - let log_type_id = ((combined_type_id as u64) / 128) as Field; - - let log_payload = array::subbvec(log_plaintext, NOTE_PRIVATE_LOG_RESERVED_FIELDS); - - (storage_slot, note_type_id, log_type_id, log_payload) -} - -unconstrained fn process_private_note_log( - contract_address: AztecAddress, - tx_hash: Field, - unique_note_hashes_in_tx: BoundedVec, - first_nullifier_in_tx: Field, - recipient: AztecAddress, - compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, - storage_slot: Field, - note_type_id: Field, - packed_note_content: BoundedVec, -) { - let discovered_notes = attempt_note_nonce_discovery( - unique_note_hashes_in_tx, - first_nullifier_in_tx, - compute_note_hash_and_nullifier, - contract_address, - storage_slot, - note_type_id, - packed_note_content, - ); - - debug_log_format( - "Discovered {0} notes from a private log", - [discovered_notes.len() as Field], - ); - - array::for_each_in_bounded_vec( - discovered_notes, - |discovered_note: DiscoveredNoteInfo, _| { - // TODO:(#10728): handle notes that fail delivery. This could be due to e.g. a temporary node connectivity - // issue, and we should perhaps not have marked the tag index as taken. - assert( - deliver_note( - contract_address, - storage_slot, - discovered_note.nonce, - packed_note_content, - discovered_note.note_hash, - discovered_note.inner_nullifier, - tx_hash, - recipient, - ), - "Failed to deliver note", - ); - }, - ); -} - -unconstrained fn process_partial_note_private_log( - contract_address: AztecAddress, - storage_slot: Field, - note_type_id: Field, - log_payload: BoundedVec, - recipient: AztecAddress, -) { - // We store the information of the partial note we found so that we can later search for the public log that will - // complete it. The tag is the first value in the payload, with the packed note content taking up the rest of it. - static_assert( - PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN == 1, - "unexpected value for PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN", - ); - - let pending = DeliveredPendingPartialNote { - note_completion_log_tag: log_payload.get(0), - storage_slot, - note_type_id, - packed_private_note_content: array::subbvec(log_payload, 1), - recipient, - }; - - DBArray::at( - contract_address, - DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_DB_SLOT, - ) - .push(pending); -} diff --git a/noir-projects/aztec-nr/aztec/src/lib.nr b/noir-projects/aztec-nr/aztec/src/lib.nr index 20eeb7bb07d..95584ea9108 100644 --- a/noir-projects/aztec-nr/aztec/src/lib.nr +++ b/noir-projects/aztec-nr/aztec/src/lib.nr @@ -1,6 +1,5 @@ mod context; mod deploy; -mod discovery; mod generators; mod hash; mod history; diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 7c78b9cc6a5..439fe705696 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,12 +1,9 @@ pub mod interfaces; pub mod initialization_utils; -use super::{ - notes::NOTES, - utils::{ - add_to_hasher, fn_has_noinitcheck, get_fn_visibility, is_fn_initializer, is_fn_internal, - is_fn_private, is_fn_view, modify_fn_body, module_has_initializer, module_has_storage, - }, +use super::utils::{ + add_to_hasher, fn_has_noinitcheck, get_fn_visibility, is_fn_initializer, is_fn_internal, + is_fn_private, is_fn_view, modify_fn_body, module_has_initializer, module_has_storage, }; use protocol_types::meta::generate_serialize_to_fields; use std::meta::type_of; @@ -84,31 +81,6 @@ comptime fn create_init_check(f: FunctionDefinition) -> Quoted { .quoted_contents() } -/// Injects a call to `aztec::discovery::discover_new_notes`, causing for new notes to be added to PXE and made -/// available for the current execution. -comptime fn create_note_discovery_call() -> Quoted { - quote { - /// Safety: note discovery returns nothing and is performed solely for its side-effects. It is therefore always - /// safe to call. - unsafe { - dep::aztec::discovery::discover_new_notes( - context.this_address(), - |packed_note_content: BoundedVec, contract_address: aztec::protocol_types::address::AztecAddress, nonce: Field, storage_slot: Field, note_type_id: Field| { - // _compute_note_hash_and_optionally_a_nullifier is a contract library method injected by `generate_contract_library_method_compute_note_hash_and_optionally_a_nullifier` - let hashes = _compute_note_hash_and_optionally_a_nullifier(contract_address, nonce, storage_slot, note_type_id, true, packed_note_content); - - Option::some( - aztec::discovery::NoteHashAndNullifier { - note_hash: hashes[0], - inner_nullifier: hashes[3], - }, - ) - }, - ) - }; - } -} - /// Private functions are executed client-side and preserve privacy. pub comptime fn private(f: FunctionDefinition) -> Quoted { let fn_abi = create_fn_abi_export(f); @@ -188,14 +160,6 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { quote {} }; - // All private functions perform note discovery, since they may need to access notes. This is slightly inefficient - // and could be improved by only doing it once we actually attempt to read any. - let note_discovery_call = if NOTES.len() > 0 { - create_note_discovery_call() - } else { - quote {} - }; - // Finally, we need to change the return type to be `PrivateCircuitPublicInputs`, which is what the Private Kernel // circuit expects. let return_value_var_name = quote { macro__returned__values }; @@ -247,7 +211,6 @@ pub comptime fn private(f: FunctionDefinition) -> Quoted { $internal_check $view_check $storage_init - $note_discovery_call }; let to_append = quote { @@ -378,19 +341,9 @@ pub comptime fn transform_unconstrained(f: FunctionDefinition) { } else { quote {} }; - - // All unconstrained functions perform note discovery, since they may need to access notes. This is slightly - // inefficient and could be improved by only doing it once we actually attempt to read any. - let note_discovery_call = if NOTES.len() > 0 { - create_note_discovery_call() - } else { - quote {} - }; - let to_prepend = quote { $context_creation $storage_init - $note_discovery_call }; let body = f.body().as_block().unwrap(); let modified_body = modify_fn_body(body, to_prepend, quote {}); diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index b6a3d111b65..1a9acb1f998 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -26,11 +26,9 @@ pub comptime fn aztec(m: Module) -> Quoted { transform_unconstrained(f); } - let contract_library_method_compute_note_hash_and_optionally_a_nullifier = - generate_contract_library_method_compute_note_hash_and_optionally_a_nullifier(); let compute_note_hash_and_optionally_a_nullifier = generate_compute_note_hash_and_optionally_a_nullifier(); - let process_log = generate_process_log(); + let process_logs = generate_process_log(); let note_exports = generate_note_exports(); let public_dispatch = generate_public_dispatch(m); let sync_notes = generate_sync_notes(); @@ -38,9 +36,8 @@ pub comptime fn aztec(m: Module) -> Quoted { quote { $note_exports $interface - $contract_library_method_compute_note_hash_and_optionally_a_nullifier $compute_note_hash_and_optionally_a_nullifier - $process_log + $process_logs $public_dispatch $sync_notes } @@ -114,158 +111,178 @@ comptime fn generate_contract_interface(m: Module) -> Quoted { } } -/// Generates a contract library method called `_compute_note_hash_and_optionally_a_nullifier` which is used for note -/// discovery (to create the `aztec::discovery::ComputeNoteHashAndNullifier` function) and to implement the -/// `compute_note_hash_and_nullifier` unconstrained contract function. -comptime fn generate_contract_library_method_compute_note_hash_and_optionally_a_nullifier() -> Quoted { +comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { + let mut max_note_content_length: u32 = 0; let notes = NOTES.entries(); + let body = if notes.len() > 0 { + max_note_content_length = notes.fold( + 0, + |acc, (_, (_, len, _, _)): (Type, (StructDefinition, u32, Field, [(Quoted, u32, bool)]))| { + if len > acc { + len + } else { + acc + } + }, + ); - // We'll produce the entire body of the function in one go and then insert it into the function. - let body: Quoted = if notes.len() == 0 { - // Contracts with no notes still implement this function to avoid having special-casing, the implementation - // simply throws immediately. - quote { panic(f"This contract does not use private notes") } - } else { - // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the - // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we - // know it we call `aztec::note::utils::compute_note_hash_and_optionally_a_nullifier` (which is the one that - // actually does the work) with the correct `unpack_content()` function. + let mut if_statements_list = &[]; - let mut if_note_type_id_match_statements_list = &[]; for i in 0..notes.len() { - let (typ, (_, serialized_note_length, _, _)) = notes[i]; - + let (typ, (_, _, _, _)) = notes[i]; let if_or_else_if = if i == 0 { quote { if } } else { quote { else if } }; - - if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back( + if_statements_list = if_statements_list.push_back( quote { - $if_or_else_if note_type_id == $typ::get_note_type_id() { - // As an extra safety check we make sure that the `packed_note_content` BoundedVec has the - // expected length, to avoid scenarios in which compute_note_hash_and_optionally_a_nullifier - // silently trims the end if the log were to be longer. - let expected_len = $serialized_note_length; - let actual_len = packed_note_content.len(); - assert( - actual_len == expected_len, - f"Expected note content of length {expected_len} but got {actual_len} for note type ID {note_type_id}" - ); - - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, contract_address, nonce, storage_slot, compute_nullifier, packed_note_content.storage()) - } - }, + $if_or_else_if note_type_id == $typ::get_note_type_id() { + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, packed_note_content) + } + }, ); } - let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {}); + let if_statements = if_statements_list.join(quote {}); quote { - $if_note_type_id_match_statements + let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot); + $if_statements else { panic(f"Unknown note type ID") } } + } else { + quote { + panic(f"No notes defined") + } }; quote { - #[contract_library_method] - unconstrained fn _compute_note_hash_and_optionally_a_nullifier( + unconstrained fn compute_note_hash_and_optionally_a_nullifier( contract_address: aztec::protocol_types::address::AztecAddress, nonce: Field, storage_slot: Field, note_type_id: Field, compute_nullifier: bool, - packed_note_content: BoundedVec, + packed_note_content: [Field; $max_note_content_length], ) -> pub [Field; 4] { $body } } } -comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { - // For historical reasons we keep this function taking an array of a length of up to the longest note (instead of a - // BoundedVec), receiving a boolean (even though we could compute the nullifier always) and returning four fields - // (even though the caller should likely perform note hash siloing on their own and not trust this). The contract - // library method `_compute_note_hash...` is affected by this. - // TODO(#11638): In the future we might remove these things as we rely less and less on this function, and then - // change the `_compute_note_hash...` contract library method to be of type - // `aztec::discovery::ComputeNoteHashAndNullifier`, simplifying other macros by removing the need to create - // intermediate lambdas that adapt their interfaces. - - let max_note_packed_length = NOTES.entries().fold( - 0, - |acc, (_, (_, len, _, _)): (Type, (StructDefinition, u32, Field, [(Quoted, u32, bool)]))| { - std::cmp::max(len, acc) - }, - ); +comptime fn generate_process_log() -> Quoted { + // This mandatory function processes a log emitted by the contract. This is currently used to recover note contents + // and deliver the note to PXE. + // The bulk of the work of this function is done by aztec::note::discovery::do_process_log, so all we need to do + // is call that function. However, one of its parameters is a lambda function that computes note hash and nullifier + // given note contents and metadata (e.g. note type id), since this behavior is contract-specific (as it + // depends on the note types implemented by each contract). + // The job of this macro is therefore to implement this lambda function and then call `do_process_log` with it. + + // A typical implementation of the lambda looks something like this: + // ``` + // |packed_note_content: BoundedVec, note_header: NoteHeader, note_type_id: Field| { + // let hashes = if note_type_id == MyNoteType::get_note_type_id() { + // assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); + // dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( + // MyNoteType::unpack_content, + // note_header, + // true, + // packed_note_content.storage(), + // ) + // } else { + // panic(f"Unknown note type id {note_type_id}") + // }; + // + // Option::some(dep::aztec::note::discovery::NoteHashesAndNullifier { + // note_hash: hashes[0], + // unique_note_hash: hashes[1], + // inner_nullifier: hashes[3], + // }) + // } + // ``` + // + // We create this implementation by iterating over the different note types, creating an `if` or `else if` clause + // for each of them and calling `compute_note_hash_and_optionally_a_nullifier` with the note's deserialization + // function, and finally produce the required `NoteHashesAndNullifier` object. - quote { - unconstrained fn compute_note_hash_and_optionally_a_nullifier( - contract_address: aztec::protocol_types::address::AztecAddress, - nonce: Field, - storage_slot: Field, - note_type_id: Field, - compute_nullifier: bool, - packed_note_content: [Field; $max_note_packed_length], - ) -> pub [Field; 4] { - _compute_note_hash_and_optionally_a_nullifier(contract_address, nonce, storage_slot, note_type_id, compute_nullifier, BoundedVec::from_array(packed_note_content)) - } + let notes = NOTES.entries(); + + let mut if_note_type_id_match_statements_list = &[]; + for i in 0..notes.len() { + let (typ, (_, packed_note_content_length, _, _)) = notes[i]; + + let if_or_else_if = if i == 0 { + quote { if } + } else { + quote { else if } + }; + + if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back( + quote { + $if_or_else_if note_type_id == $typ::get_note_type_id() { + // As an extra safety check we make sure that the packed_note_content bounded vec has the + // expected length, to avoid scenarios in which compute_note_hash_and_optionally_a_nullifier + // silently trims the end if the log were to be longer. + let expected_len = $packed_note_content_length; + let actual_len = packed_note_content.len(); + assert( + actual_len == expected_len, + f"Expected note content of length {expected_len} but got {actual_len} for note type id {note_type_id}" + ); + + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, true, packed_note_content.storage()) + } + }, + ); } -} -comptime fn generate_process_log() -> Quoted { - // This mandatory function processes a log emitted by the contract. This is currently used to process private logs - // and perform note discovery of either private notes or partial notes. - // The bulk of the work of this function is done by aztec::discovery::do_process_log, so all we need to do is call - // that function. We use the contract library method injected by - // `generate_contract_library_method_compute_note_hash_and_optionally_a_nullifier` in order to create the required - // `aztec::discovery::ComputeNoteHashAndNullifier` function. - - // We'll produce the entire body of the function in one go and then insert it into the function. - let notes = NOTES.entries(); - let body = if notes.len() == 0 { - // Contracts with no notes still implement this function to avoid having special-casing, the implementation - // simply throws immediately. - quote { panic(f"This contract does not use private notes") } - } else { + let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {}); + + let body = if notes.len() > 0 { quote { // Because this unconstrained function is injected after the contract is processed by the macros, it'll not // be modified by the macros that alter unconstrained functions. As such, we need to manually inject the // unconstrained execution context since it will not be available otherwise. - let context = aztec::context::unconstrained_context::UnconstrainedContext::new(); + let context = dep::aztec::context::unconstrained_context::UnconstrainedContext::new(); - // TODO(#10727): allow other contracts to process logs and deliver notes - let contract_address = context.this_address(); - - aztec::discovery::private_logs::do_process_log( - contract_address, + dep::aztec::note::discovery::do_process_log( + context, log_plaintext, tx_hash, unique_note_hashes_in_tx, first_nullifier_in_tx, recipient, - |packed_note_content: BoundedVec, contract_address: aztec::protocol_types::address::AztecAddress, nonce: Field, storage_slot: Field, note_type_id: Field| { - let hashes = _compute_note_hash_and_optionally_a_nullifier(contract_address, nonce, storage_slot, note_type_id, true, packed_note_content); + |packed_note_content: BoundedVec, note_header, note_type_id| { + let hashes = $if_note_type_id_match_statements + else { + panic(f"Unknown note type id {note_type_id}") + }; Option::some( - aztec::discovery::NoteHashAndNullifier { + dep::aztec::note::discovery::NoteHashesAndNullifier { note_hash: hashes[0], + unique_note_hash: hashes[1], inner_nullifier: hashes[3], }, ) } ); } + } else { + quote { + panic(f"No notes defined") + } }; quote { unconstrained fn process_log( - log_plaintext: BoundedVec, + log_plaintext: BoundedVec, tx_hash: Field, - unique_note_hashes_in_tx: BoundedVec, + unique_note_hashes_in_tx: BoundedVec, first_nullifier_in_tx: Field, recipient: aztec::protocol_types::address::AztecAddress, ) { @@ -288,7 +305,7 @@ comptime fn generate_note_exports() -> Quoted { comptime fn generate_sync_notes() -> Quoted { quote { unconstrained fn sync_notes() { - aztec::oracle::note_discovery::sync_notes(); + aztec::oracle::notes::sync_notes(); } } } diff --git a/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr b/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr new file mode 100644 index 00000000000..ddbcd80e9de --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr @@ -0,0 +1,130 @@ +use std::static_assert; + +use crate::{ + context::unconstrained_context::UnconstrainedContext, note::note_header::NoteHeader, + oracle::note_discovery::deliver_note, utils::array, +}; + +use dep::protocol_types::{ + address::AztecAddress, + constants::{MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS}, + hash::compute_note_hash_nonce, +}; + +// We reserve two fields in the note log that are not part of the note content: one for the storage slot, and one for +// the note type id. +global NOTE_LOG_RESERVED_FIELDS: u32 = 2; +pub global MAX_NOTE_SERIALIZED_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - NOTE_LOG_RESERVED_FIELDS; + +pub struct NoteHashesAndNullifier { + pub note_hash: Field, + pub unique_note_hash: Field, + pub inner_nullifier: Field, +} + +/// Processes a log given its plaintext by trying to find notes encoded in it. This process involves the discovery of +/// the nonce of any such notes, which requires knowledge of the transaction hash in which the notes would've been +/// created, along with the list of unique note hashes in said transaction. +/// +/// Additionally, this requires a `compute_note_hash_and_nullifier` lambda that is able to compute these values for any +/// note in the contract given their contents. A typical implementation of such a function would look like this: +/// +/// ``` +/// |packed_note_content, note_header, note_type_id| { +/// let hashes = if note_type_id == MyNoteType::get_note_type_id() { +/// assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); +/// dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( +/// MyNoteType::unpack_content, +/// note_header, +/// true, +/// packed_note_content.storage(), +/// ) +/// } else { +/// panic(f"Unknown note type id {note_type_id}") +/// }; +/// +/// Option::some(dep::aztec::oracle::management::NoteHashesAndNullifier { +/// note_hash: hashes[0], +/// unique_note_hash: hashes[1], +/// inner_nullifier: hashes[3], +/// }) +/// } +/// ``` +pub unconstrained fn do_process_log( + context: UnconstrainedContext, + log_plaintext: BoundedVec, + tx_hash: Field, + unique_note_hashes_in_tx: BoundedVec, + first_nullifier_in_tx: Field, + recipient: AztecAddress, + compute_note_hash_and_nullifier: fn[Env](BoundedVec, NoteHeader, Field) -> Option, +) { + let (storage_slot, note_type_id, packed_note_content) = + destructure_log_plaintext(log_plaintext); + + // We need to find the note's nonce, which is the one that results in one of the unique note hashes from tx_hash + for_each_in_bounded_vec( + unique_note_hashes_in_tx, + |expected_unique_note_hash, i| { + let candidate_nonce = compute_note_hash_nonce(first_nullifier_in_tx, i); + + let header = NoteHeader::new(context.this_address(), candidate_nonce, storage_slot); + + // TODO(#11157): handle failed note_hash_and_nullifier computation + let hashes = + compute_note_hash_and_nullifier(packed_note_content, header, note_type_id).unwrap(); + + if hashes.unique_note_hash == expected_unique_note_hash { + // TODO(#10726): push these into a vec to deliver all at once instead of having one oracle call per note + + assert( + deliver_note( + context.this_address(), // TODO(#10727): allow other contracts to deliver notes + storage_slot, + candidate_nonce, + packed_note_content, + hashes.note_hash, + hashes.inner_nullifier, + tx_hash, + recipient, + ), + "Failed to deliver note", + ); + + // We don't exit the loop - it is possible (though rare) for the exact same note content to be present + // multiple times in the same transaction with different nonces. This typically doesn't happen due to + // notes containing random values in order to hide their contents. + } + }, + ); +} + +unconstrained fn destructure_log_plaintext( + log_plaintext: BoundedVec, +) -> (Field, Field, BoundedVec) { + assert(log_plaintext.len() >= NOTE_LOG_RESERVED_FIELDS); + + // If NOTE_LOG_RESERVED_FIELDS is changed, causing the assertion below to fail, then the declarations for + // `storage_slot` and `note_type_id` must be updated as well. + static_assert( + NOTE_LOG_RESERVED_FIELDS == 2, + "unepxected value for NOTE_LOG_RESERVED_FIELDS", + ); + let storage_slot = log_plaintext.get(0); + let note_type_id = log_plaintext.get(1); + + let packed_note_content = array::subbvec(log_plaintext, NOTE_LOG_RESERVED_FIELDS); + + (storage_slot, note_type_id, packed_note_content) +} + +fn for_each_in_bounded_vec( + vec: BoundedVec, + f: fn[Env](T, u32) -> (), +) { + for i in 0..MaxLen { + if i < vec.len() { + f(vec.get_unchecked(i), i); + } + } +} diff --git a/noir-projects/aztec-nr/aztec/src/note/mod.nr b/noir-projects/aztec-nr/aztec/src/note/mod.nr index 6ada1a1fabf..593a00b03ad 100644 --- a/noir-projects/aztec-nr/aztec/src/note/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/mod.nr @@ -1,4 +1,5 @@ pub mod constants; +pub mod discovery; pub mod lifecycle; pub mod note_getter; pub mod note_getter_options; diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 8bb4c7fbcff..94ed825f986 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -17,8 +17,8 @@ where } pub trait NullifiableNote { - /// Returns the non-siloed nullifier (also called inner-nullifier), which will be later siloed by contract address - /// by the kernels before being committed to the state tree. + /// Returns the non-siloed nullifier, which will be later siloed by contract address by the kernels before being + /// committed to the state tree. /// /// This function MUST be called with the correct note hash for consumption! It will otherwise silently fail and /// compute an incorrect value. The reason why we receive this as an argument instead of computing it ourselves diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 248a3fc3e11..730540ec021 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -4,13 +4,9 @@ use crate::{ utils::array, }; -use dep::protocol_types::{ - address::AztecAddress, - hash::{ - compute_siloed_note_hash, - compute_siloed_nullifier as compute_siloed_nullifier_from_preimage, - compute_unique_note_hash, - }, +use dep::protocol_types::hash::{ + compute_siloed_note_hash, compute_siloed_nullifier as compute_siloed_nullifier_from_preimage, + compute_unique_note_hash, }; pub fn compute_siloed_nullifier( @@ -120,13 +116,9 @@ where compute_note_hash_for_nullify_internal(note, note_hash_for_read_request) } -// TODO (#11638): simplify or remove this function by inlining it in the `_compute_note_hash_and_nullifier` contract -// library method that is autogenerated by macros. pub unconstrained fn compute_note_hash_and_optionally_a_nullifier( unpack_content: fn([Field; N]) -> T, - contract_address: AztecAddress, - nonce: Field, - storage_slot: Field, + note_header: NoteHeader, compute_nullifier: bool, packed_note_content: [Field; S], ) -> [Field; 4] @@ -134,11 +126,11 @@ where T: NoteInterface + NullifiableNote, { let mut note = unpack_content(array::subarray(packed_note_content, 0)); - note.set_header(NoteHeader::new(contract_address, nonce, storage_slot)); + note.set_header(note_header); let note_hash = note.compute_note_hash(); - let siloed_note_hash = compute_siloed_note_hash(contract_address, note_hash); - let unique_note_hash = compute_unique_note_hash(nonce, siloed_note_hash); + let siloed_note_hash = compute_siloed_note_hash(note_header.contract_address, note_hash); + let unique_note_hash = compute_unique_note_hash(note_header.nonce, siloed_note_hash); let inner_nullifier = if compute_nullifier { note.compute_nullifier_without_context() diff --git a/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr b/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr index 3c3dfbe432b..8d4c2848991 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr @@ -1,14 +1,5 @@ -use crate::discovery::MAX_NOTE_PACKED_LEN; -use dep::protocol_types::{address::AztecAddress, log_with_tx_data::LogWithTxData}; - -/// Finds new notes that may have been sent to all registered accounts in PXE in the current contract and makes them available -/// for later querying via the `get_notes` oracle. -pub unconstrained fn sync_notes() { - sync_notes_oracle(); -} - -#[oracle(syncNotes)] -unconstrained fn sync_notes_oracle() {} +use crate::note::discovery::MAX_NOTE_SERIALIZED_LEN; +use dep::protocol_types::address::AztecAddress; /// Informs PXE of a note's existence so that it can later retrieved by the `getNotes` oracle. The note will be scoped /// to `contract_address`, meaning other contracts will not be able to access it unless authorized. @@ -27,7 +18,7 @@ pub unconstrained fn deliver_note( contract_address: AztecAddress, storage_slot: Field, nonce: Field, - content: BoundedVec, + content: BoundedVec, note_hash: Field, nullifier: Field, tx_hash: Field, @@ -45,27 +36,14 @@ pub unconstrained fn deliver_note( ) } -/// Fetches a log from the node that has the corresponding `tag`. The log can be either a public or a private log, and -/// the tag is the first field in the log's content. Returns `Option::none` if no such log exists. Throws if more than -/// one log with that tag exists. -/// Public logs have an extra field included at the beginning with the address of the contract that emtitted them. -// TODO(#11627): handle multiple logs with the same tag. -// TODO(#10273): improve contract siloing of logs, don't introduce an extra field. -pub unconstrained fn get_log_by_tag(tag: Field) -> Option { - get_log_by_tag_oracle(tag) -} - #[oracle(deliverNote)] unconstrained fn deliver_note_oracle( contract_address: AztecAddress, storage_slot: Field, nonce: Field, - content: BoundedVec, + content: BoundedVec, note_hash: Field, nullifier: Field, tx_hash: Field, recipient: AztecAddress, ) -> bool {} - -#[oracle(getLogByTag)] -unconstrained fn get_log_by_tag_oracle(tag: Field) -> Option {} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index ef2b1cbcc99..f1d779c43c4 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -3,7 +3,6 @@ use crate::{note::{note_header::NoteHeader, note_interface::NoteInterface}, util use dep::protocol_types::{ address::AztecAddress, indexed_tagging_secret::{INDEXED_TAGGING_SECRET_LENGTH, IndexedTaggingSecret}, - traits::{Deserialize, FromField}, }; /// Notifies the simulator that a note has been created, so that it can be returned in future read requests in the same @@ -32,15 +31,14 @@ pub fn notify_created_note( /// the same transaction. This note should only be removed to the non-volatile database if its nullifier is found in an /// actual block. pub fn notify_nullified_note(nullifier: Field, note_hash: Field, counter: u32) { - /// Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to - /// call. + /// Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe + /// to call. unsafe { notify_nullified_note_oracle_wrapper(nullifier, note_hash, counter) }; } /// Notifies the simulator that a non-note nullifier has been created, so that it can be used for note nonces. pub fn notify_created_nullifier(nullifier: Field) { - /// Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to - /// call. + // This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to call. unsafe { notify_created_nullifier_oracle_wrapper(nullifier) }; } @@ -171,6 +169,7 @@ pub unconstrained fn get_notes, { + sync_notes_oracle_wrapper(); let fields = get_notes_oracle_wrapper( storage_slot, num_selects, @@ -269,3 +268,20 @@ unconstrained fn increment_app_tagging_secret_index_as_sender_oracle( _sender: AztecAddress, _recipient: AztecAddress, ) {} + +/// Finds new notes that may have been sent to all registered accounts in PXE in the current contract and makes them available +/// for later querying via the `get_notes` oracle. +pub fn sync_notes() { + /// Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe + /// to call. + unsafe { + sync_notes_oracle_wrapper(); + } +} + +unconstrained fn sync_notes_oracle_wrapper() { + sync_notes_oracle(); +} + +#[oracle(syncNotes)] +unconstrained fn sync_notes_oracle() {} diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/append.nr b/noir-projects/aztec-nr/aztec/src/utils/array/append.nr deleted file mode 100644 index dbc370346c5..00000000000 --- a/noir-projects/aztec-nr/aztec/src/utils/array/append.nr +++ /dev/null @@ -1,48 +0,0 @@ -/// Appends two `BoundedVec`s together, returning one that contains all of the elements of the first one followed by all -/// of the elements of the second one. The resulting `BoundedVec` can have any arbitrary maximum length, but it must be -/// large enough to fit all of the elements of both the first and second vectors. -pub fn append( - a: BoundedVec, - b: BoundedVec, -) -> BoundedVec { - let mut dst = BoundedVec::new(); - - dst.extend_from_bounded_vec(a); - dst.extend_from_bounded_vec(b); - - dst -} - -mod test { - use super::append; - - #[test] - unconstrained fn append_empty_vecs() { - let a: BoundedVec<_, 3> = BoundedVec::new(); - let b: BoundedVec<_, 14> = BoundedVec::new(); - - let result: BoundedVec = append(a, b); - - assert_eq(result.len(), 0); - assert_eq(result.storage(), std::mem::zeroed()); - } - - #[test] - unconstrained fn append_non_empty_vecs() { - let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]); - let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]); - - let result: BoundedVec = append(a, b); - - assert_eq(result.len(), 6); - assert_eq(result.storage(), [1, 2, 3, 4, 5, 6, std::mem::zeroed(), std::mem::zeroed()]); - } - - #[test(should_fail_with = "out of bounds")] - unconstrained fn append_non_empty_vecs_insufficient_max_len() { - let a: BoundedVec<_, 3> = BoundedVec::from_array([1, 2, 3]); - let b: BoundedVec<_, 14> = BoundedVec::from_array([4, 5, 6]); - - let _: BoundedVec = append(a, b); - } -} diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr index 291dc924166..ef46a00a5a2 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr @@ -1,19 +1,7 @@ -mod append; mod collapse; mod subarray; mod subbvec; -pub use append::append; pub use collapse::collapse; pub use subarray::subarray; pub use subbvec::subbvec; - -// This will eventually be replaced by `BoundedVec::for_each`, once that's implemented. -pub unconstrained fn for_each_in_bounded_vec( - vec: BoundedVec, - f: fn[Env](T, u32) -> (), -) { - for i in 0..vec.len() { - f(vec.get_unchecked(i), i); - } -} diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr b/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr index c457b7695d1..f08bed65942 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/array/subbvec.nr @@ -16,14 +16,14 @@ use crate::utils::array; /// let baz: BoundedVec<_, 10> = subbvec(foo, 3); // fails - we can't return 10 elements since only 7 remain /// ``` pub fn subbvec( - bvec: BoundedVec, + vec: BoundedVec, offset: u32, ) -> BoundedVec { // from_parts_unchecked does not verify that the elements past len are zeroed, but that is not an issue in our case // because we're constructing the new storage array as a subarray of the original one (which should have zeroed // storage past len), guaranteeing correctness. This is because `subarray` does not allow extending arrays past // their original length. - BoundedVec::from_parts_unchecked(array::subarray(bvec.storage(), offset), bvec.len() - offset) + BoundedVec::from_parts_unchecked(array::subarray(vec.storage(), offset), vec.len() - offset) } mod test { diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 554ebbad2df..efa1471a26b 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -140,11 +140,9 @@ pub contract Counter { unconstrained fn inclusion_proofs() { let initial_value = 5; let (env, contract_address, owner) = test::setup(initial_value); - env.impersonate(contract_address); - env.advance_block_by(1); - sync_notes(); + env.impersonate(contract_address); let counter_slot = Counter::storage_layout().counters.slot; let owner_slot = derive_storage_slot_in_map(counter_slot, owner); let mut options = NoteViewerOptions::new(); @@ -161,7 +159,6 @@ pub contract Counter { destroy_note(&mut env.private(), old_note); env.advance_block_by(1); - sync_notes(); env.private().get_block_header().prove_note_is_nullified(old_note, &mut env.private()); env.private().get_block_header().prove_note_inclusion(old_note); @@ -190,7 +187,6 @@ pub contract Counter { // Checking that the note was discovered from private logs env.advance_block_by(1); - sync_notes(); env.impersonate(contract_address); let counter_slot = Counter::storage_layout().counters.slot; let owner_slot = derive_storage_slot_in_map(counter_slot, owner); @@ -211,7 +207,6 @@ pub contract Counter { // Checking that the note was discovered from private logs env.advance_block_by(1); - sync_notes(); let notes: BoundedVec = view_notes(owner_slot, options); assert(get_counter(owner) == 7); assert(notes.len() == 3); @@ -225,7 +220,6 @@ pub contract Counter { // Checking that the note was discovered from private logs env.advance_block_by(1); - sync_notes(); let notes: BoundedVec = view_notes(owner_slot, options); assert(notes.len() == 4); assert(get_counter(owner) == 7); @@ -238,7 +232,6 @@ pub contract Counter { // Checking that the note was discovered from private logs env.advance_block_by(1); - sync_notes(); let notes: BoundedVec = view_notes(owner_slot, options); assert(get_counter(owner) == 6); assert(notes.len() == 4); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr index e3b90d9be89..c5c37d539cb 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr @@ -31,7 +31,6 @@ pub mod storage; pub mod validate; pub mod meta; pub mod indexed_tagging_secret; -pub mod log_with_tx_data; pub use abis::kernel_circuit_public_inputs::{ PrivateKernelCircuitPublicInputs, PrivateToRollupKernelCircuitPublicInputs, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/log_with_tx_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/log_with_tx_data.nr deleted file mode 100644 index 9ced1852d10..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/log_with_tx_data.nr +++ /dev/null @@ -1,14 +0,0 @@ -use crate::constants::{MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS}; - -/// The contents of a public log, plus contextual information about the transaction in which the log was emitted. This -/// is the data required in order to discover notes that are being delivered in a log. -// TODO(#11639): this could also be used to fetch private logs, but the `BoundedVec` maximum length is that of a public -// log. -pub struct LogWithTxData { - pub log_content: BoundedVec, - pub tx_hash: Field, - /// The array of new note hashes created by `tx_hash` - pub unique_note_hashes_in_tx: BoundedVec, - /// The first nullifier created by `tx_hash` - pub first_nullifier_in_tx: Field, -} diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index f9acb4764ad..64004a2cdb2 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -16,7 +16,6 @@ export * from './gas_settings.js'; export * from './global_variables.js'; export * from './block_header.js'; export * from './indexed_tagging_secret.js'; -export * from './log_with_tx_data.js'; export * from './kernel/private_to_rollup_accumulated_data.js'; export * from './kernel/combined_constant_data.js'; export * from './kernel/private_to_rollup_kernel_circuit_public_inputs.js'; diff --git a/yarn-project/circuits.js/src/structs/log_with_tx_data.ts b/yarn-project/circuits.js/src/structs/log_with_tx_data.ts deleted file mode 100644 index d4e1d80b1a2..00000000000 --- a/yarn-project/circuits.js/src/structs/log_with_tx_data.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '../constants.gen.js'; - -// TypeScript representation of the Noir protocol_types::log_with_tx_data::LogWithTxData struct. -export class LogWithTxData { - constructor( - public logContent: Fr[], - public txHash: Fr, - public uniqueNoteHashesInTx: Fr[], - public firstNullifierInTx: Fr, - ) {} - - toNoirSerialization(): (Fr | Fr[])[] { - return [ - ...toBoundedVecSerialization(this.logContent, PUBLIC_LOG_DATA_SIZE_IN_FIELDS), - this.txHash, - ...toBoundedVecSerialization(this.uniqueNoteHashesInTx, MAX_NOTE_HASHES_PER_TX), - this.firstNullifierInTx, - ]; - } - - static noirSerializationOfEmpty(): (Fr | Fr[])[] { - return new LogWithTxData([], new Fr(0), [], new Fr(0)).toNoirSerialization(); - } -} - -function toBoundedVecSerialization(array: Fr[], maxLength: number) { - if (array.length > maxLength) { - throw new Error( - `An array of length ${array.length} cannot be converted to a BoundedVec of max length ${maxLength}`, - ); - } - - return [array.concat(Array(maxLength - array.length).fill(new Fr(0))), new Fr(array.length)]; -} diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 2dc6c4d2bfa..2220f41fdee 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -24,10 +24,8 @@ import { IndexedTaggingSecret, type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, - LogWithTxData, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, - PUBLIC_LOG_DATA_SIZE_IN_FIELDS, PrivateLog, PublicLog, computeAddressSecret, @@ -44,7 +42,6 @@ import { import { timesParallel } from '@aztec/foundation/collection'; import { poseidon2Hash } from '@aztec/foundation/crypto'; import { createLogger } from '@aztec/foundation/log'; -import { BufferReader } from '@aztec/foundation/serialize'; import { type KeyStore } from '@aztec/key-store'; import { type AcirSimulator, @@ -710,45 +707,8 @@ export class SimulatorOracle implements DBOracle { }); } - public async getLogByTag(tag: Fr): Promise { - const logs = await this.aztecNode.getLogsByTags([tag]); - const logsForTag = logs[0]; - - this.log.debug(`Got ${logsForTag.length} logs for tag ${tag}`); - - if (logsForTag.length == 0) { - return null; - } else if (logsForTag.length > 1) { - // TODO(#11627): handle this case - throw new Error( - `Got ${logsForTag.length} logs for tag ${tag}. getLogByTag currently only supports a single log per tag`, - ); - } - - const log = logsForTag[0]; - - // getLogsByTag doesn't have all of the information that we need (notably note hashes and the first nullifier), so - // we need to make a second call to the node for `getTxEffect`. - // TODO(#9789): bundle this information in the `getLogsByTag` call. - const txEffect = await this.aztecNode.getTxEffect(log.txHash); - if (txEffect == undefined) { - throw new Error(`Unexpected: failed to retrieve tx effects for tx ${log.txHash} which is known to exist`); - } - - const reader = BufferReader.asReader(log.logData); - const logArray = reader.readArray(PUBLIC_LOG_DATA_SIZE_IN_FIELDS, Fr); - - // Public logs always take up all available fields by padding with zeroes, and the length of the originally emitted - // log is lost. Until this is improved, we simply remove all of the zero elements (which are expected to be at the - // end). - // TODO(#11636): use the actual log length. - const trimmedLog = logArray.filter(x => !x.isZero()); - - return new LogWithTxData(trimmedLog, log.txHash.hash, txEffect.data.noteHashes, txEffect.data.nullifiers[0]); - } - public async removeNullifiedNotes(contractAddress: AztecAddress) { - this.log.verbose('Searching for nullifiers of known notes', { contract: contractAddress }); + this.log.verbose('Removing nullified notes', { contract: contractAddress }); for (const recipient of await this.keyStore.getAccounts()) { const currentNotesForRecipient = await this.db.getNotes({ contractAddress, owner: recipient }); diff --git a/yarn-project/simulator/src/acvm/deserialize.ts b/yarn-project/simulator/src/acvm/deserialize.ts index af6794196a8..57ad9fe8d0d 100644 --- a/yarn-project/simulator/src/acvm/deserialize.ts +++ b/yarn-project/simulator/src/acvm/deserialize.ts @@ -31,7 +31,7 @@ export function frToBoolean(fr: Fr): boolean { /** * Converts a Noir BoundedVec of Fields into an Fr array. Note that BoundedVecs are structs, and therefore translated as - * two separate ACVMField values (an array and a single field). + * two separate ACVMField arrays. * * @param storage The array with the BoundedVec's storage (i.e. BoundedVec::storage()) * @param length The length of the BoundedVec (i.e. BoundedVec::len()) diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 77f7ab27845..3d2501a3a2e 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -1,12 +1,11 @@ import { MerkleTreeId, UnencryptedL2Log } from '@aztec/circuit-types'; -import { LogWithTxData } from '@aztec/circuits.js'; import { FunctionSelector, NoteSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { type ACVMField } from '../acvm_types.js'; import { frToBoolean, frToNumber, fromACVMField, fromBoundedVec } from '../deserialize.js'; -import { toACVMField, toACVMFieldSingleOrArray } from '../serialize.js'; +import { toACVMField } from '../serialize.js'; import { type TypedOracle } from './typed_oracle.js'; /** @@ -405,16 +404,6 @@ export class Oracle { return toACVMField(true); } - async getLogByTag([tag]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> { - const log = await this.typedOracle.getLogByTag(fromACVMField(tag)); - - if (log == null) { - return [toACVMField(0), ...LogWithTxData.noirSerializationOfEmpty().map(toACVMFieldSingleOrArray)]; - } else { - return [toACVMField(1), ...log.toNoirSerialization().map(toACVMFieldSingleOrArray)]; - } - } - async dbStore([contractAddress]: ACVMField[], [slot]: ACVMField[], values: ACVMField[]) { await this.typedOracle.dbStore( AztecAddress.fromField(fromACVMField(contractAddress)), diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index afa1dcb66ea..6eac05947f3 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -13,7 +13,6 @@ import { type IndexedTaggingSecret, type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, - type LogWithTxData, } from '@aztec/circuits.js'; import { type FunctionSelector, type NoteSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; @@ -247,10 +246,6 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('deliverNote'); } - getLogByTag(_tag: Fr): Promise { - throw new OracleMethodNotAvailableError('getLogByTag'); - } - dbStore(_contractAddress: AztecAddress, _key: Fr, _values: Fr[]): Promise { throw new OracleMethodNotAvailableError('dbStore'); } diff --git a/yarn-project/simulator/src/acvm/serialize.ts b/yarn-project/simulator/src/acvm/serialize.ts index d76f0d6438c..0ae28ed6ce5 100644 --- a/yarn-project/simulator/src/acvm/serialize.ts +++ b/yarn-project/simulator/src/acvm/serialize.ts @@ -39,13 +39,6 @@ export function toACVMField( return `0x${adaptBufferSize(buffer).toString('hex')}`; } -/** - * Converts a single value or an array of single values into the equivalent ACVM field representation. - */ -export function toACVMFieldSingleOrArray(value: Fr | Fr[]) { - return Array.isArray(value) ? value.map(toACVMField) : toACVMField(value); -} - /** * Inserts a list of ACVM fields to a witness. * @param witnessStartIndex - The index where to start inserting the fields. diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 5be0103f8b1..2f66724b614 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -278,13 +278,6 @@ export class ClientExecutionContext extends ViewDataOracle { noteHash: Fr, counter: number, ) { - this.log.debug(`Notified of new note with inner hash ${noteHash}`, { - contractAddress: this.callContext.contractAddress, - storageSlot, - noteTypeId, - counter, - }); - const note = new Note(noteItems); this.noteCache.addNewNote( { diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index c1a1e2d7baf..594af643bcc 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -12,7 +12,6 @@ import { type ContractInstance, type IndexedTaggingSecret, type KeyValidationRequest, - type LogWithTxData, } from '@aztec/circuits.js'; import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; @@ -258,14 +257,6 @@ export interface DBOracle extends CommitmentsDB { recipient: AztecAddress, ): Promise; - /** - * Searches for a log with the corresponding `tag` and returns it along with contextual transaction information. - * Returns null if no such log exists, and throws if more than one exists. - * - * @param tag - The log tag to search for. - */ - getLogByTag(tag: Fr): Promise; - /** * Removes all of a contract's notes that have been nullified from the note database. */ diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 36af33005e6..c8797415dd8 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -7,7 +7,6 @@ import { Note, PublicExecutionRequest, TxExecutionRequest, - type TxScopedL2Log, } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, @@ -248,9 +247,6 @@ describe('Private Execution test suite', () => { }, ); - oracle.syncTaggedLogs.mockImplementation((_, __, ___) => Promise.resolve(new Map())); - oracle.dbLoad.mockImplementation((_, __) => Promise.resolve(null)); - node = mock(); node.getPublicStorageAt.mockImplementation( (_address: AztecAddress, _storageSlot: Fr, _blockNumber: L2BlockNumber) => { diff --git a/yarn-project/simulator/src/client/unconstrained_execution.test.ts b/yarn-project/simulator/src/client/unconstrained_execution.test.ts index e1779622389..11163cef275 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.test.ts @@ -1,4 +1,4 @@ -import { type AztecNode, type FunctionCall, Note, type TxScopedL2Log } from '@aztec/circuit-types'; +import { type AztecNode, type FunctionCall, Note } from '@aztec/circuit-types'; import { BlockHeader, CompleteAddress } from '@aztec/circuits.js'; import { FunctionSelector, FunctionType, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -72,9 +72,6 @@ describe('Unconstrained Execution test suite', () => { })), ); - oracle.syncTaggedLogs.mockImplementation((_, __, ___) => Promise.resolve(new Map())); - oracle.dbLoad.mockImplementation((_, __) => Promise.resolve(null)); - const execRequest: FunctionCall = { name: artifact.name, to: contractAddress, diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 847352498cb..0ca67be9f6e 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -12,7 +12,6 @@ import { type ContractInstance, type IndexedTaggingSecret, type KeyValidationRequest, - type LogWithTxData, } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -329,10 +328,6 @@ export class ViewDataOracle extends TypedOracle { await this.db.deliverNote(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient); } - public override getLogByTag(tag: Fr): Promise { - return this.db.getLogByTag(tag); - } - public override dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise { if (!contractAddress.equals(this.contractAddress)) { // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 40d112f8937..2d0a3de8b29 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -28,7 +28,6 @@ import { IndexedTaggingSecret, type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, - type LogWithTxData, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, @@ -1075,10 +1074,6 @@ export class TXE implements TypedOracle { throw new Error('deliverNote'); } - async getLogByTag(tag: Fr): Promise { - return await this.simulatorOracle.getLogByTag(tag); - } - // AVM oracles async avmOpcodeCall(targetContractAddress: AztecAddress, args: Fr[], isStaticCall: boolean): Promise {