diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 4c07e444bee..f7feee54aa4 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -321,6 +321,16 @@ export class AztecNodeService implements AztecNode { return committedDb.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGES_TREE, leafIndex); } + /** + * Find the index of the given nullifier. + * @param nullifier - The nullifier to search for. + * @returns The index of the given leaf in the nullifier tree or undefined if not found. + */ + public async findNullifierIndex(nullifier: Fr): Promise { + const committedDb = await this.#getWorldState(); + return committedDb.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); + } + /** * Gets the storage value at the given contract slot. * @param contract - Address of the contract to query. diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 3d477b31a06..72f42355be8 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -18,7 +18,7 @@ import { PartialAddress, PublicCallRequest, } from '@aztec/circuits.js'; -import { computeCommitmentNonce } from '@aztec/circuits.js/abis'; +import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis'; import { encodeArguments } from '@aztec/foundation/abi'; import { padArrayEnd } from '@aztec/foundation/collection'; import { Fr, Point } from '@aztec/foundation/fields'; @@ -41,6 +41,7 @@ import { LogType, NodeInfo, NotePreimage, + PublicKey, SimulationError, Tx, TxExecutionRequest, @@ -198,6 +199,44 @@ export class AztecRPCServer implements AztecRPC { return ownerNotes.map(n => n.notePreimage); } + public async addNote( + contractAddress: AztecAddress, + storageSlot: Fr, + preimage: NotePreimage, + nonce: Fr, + account: PublicKey, + ) { + const { innerNoteHash, siloedNoteHash, uniqueSiloedNoteHash, innerNullifier } = + await this.simulator.computeNoteHashAndNullifier(contractAddress, nonce, storageSlot, preimage.items); + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386) + // This can always be `uniqueSiloedNoteHash` once notes added from public also include nonces. + const noteHashToLookUp = nonce.isZero() ? siloedNoteHash : uniqueSiloedNoteHash; + const index = await this.node.findCommitmentIndex(noteHashToLookUp.toBuffer()); + if (index === undefined) { + throw new Error('Note does not exist.'); + } + + const wasm = await CircuitsWasm.get(); + const siloedNullifier = siloNullifier(wasm, contractAddress, innerNullifier!); + const nullifierIndex = await this.node.findNullifierIndex(siloedNullifier); + if (nullifierIndex !== undefined) { + throw new Error('The note has been destroyed.'); + } + + // TODO - Should not modify the db while syncing. + await this.db.addNoteSpendingInfo({ + contractAddress, + storageSlot, + notePreimage: preimage, + nonce, + innerNoteHash, + siloedNullifier, + index, + publicKey: account, + }); + } + public async getNoteNonces( contractAddress: AztecAddress, storageSlot: Fr, diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 0d22e9b27f4..fe17337651f 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Fr, GrumpkinPrivateKey, PartialAddress } from '@aztec/circuits.js'; +import { AztecAddress, Fr, GrumpkinPrivateKey, PartialAddress, Point } from '@aztec/circuits.js'; import { AuthWitness, AztecRPC, @@ -74,6 +74,9 @@ export abstract class BaseWallet implements Wallet { getPublicStorageAt(contract: AztecAddress, storageSlot: Fr): Promise { return this.rpc.getPublicStorageAt(contract, storageSlot); } + addNote(contract: AztecAddress, storageSlot: Fr, preimage: NotePreimage, nonce: Fr, account: Point): Promise { + return this.rpc.addNote(contract, storageSlot, preimage, nonce, account); + } getNoteNonces(contract: AztecAddress, storageSlot: Fr, preimage: NotePreimage, txHash: TxHash): Promise { return this.rpc.getNoteNonces(contract, storageSlot, preimage, txHash); } diff --git a/yarn-project/types/src/interfaces/aztec-node.ts b/yarn-project/types/src/interfaces/aztec-node.ts index bac696c3850..de41c581c6a 100644 --- a/yarn-project/types/src/interfaces/aztec-node.ts +++ b/yarn-project/types/src/interfaces/aztec-node.ts @@ -16,12 +16,17 @@ import { Tx, TxHash, } from '../index.js'; +import { NullifierProvider } from './nullifier_provider.js'; /** * The aztec node. * We will probably implement the additional interfaces by means other than Aztec Node as it's currently a privacy leak */ -export interface AztecNode extends DataCommitmentProvider, L1ToL2MessageProvider, ContractCommitmentProvider { +export interface AztecNode + extends DataCommitmentProvider, + L1ToL2MessageProvider, + ContractCommitmentProvider, + NullifierProvider { /** * Method to determine if the node is ready to accept transactions. * @returns - Flag indicating the readiness for tx submission. diff --git a/yarn-project/types/src/interfaces/aztec_rpc.ts b/yarn-project/types/src/interfaces/aztec_rpc.ts index 2c5c5a00e87..94217c10a83 100644 --- a/yarn-project/types/src/interfaces/aztec_rpc.ts +++ b/yarn-project/types/src/interfaces/aztec_rpc.ts @@ -7,6 +7,7 @@ import { L2BlockL2Logs, L2Tx, NotePreimage, + PublicKey, Tx, TxExecutionRequest, TxHash, @@ -169,6 +170,22 @@ export interface AztecRPC { */ getPublicStorageAt(contract: AztecAddress, storageSlot: Fr): Promise; + /** + * Adds a note to the database. Throw if the note hash of the note doesn't exist in the tree. + * @param contract - The contract address of the note. + * @param storageSlot - The storage slot of the note. + * @param preimage - The note preimage. + * @param nonce - The nonce of the note. + * @param account - The public key of the account the note is associated with. + */ + addNote( + contract: AztecAddress, + storageSlot: Fr, + preimage: NotePreimage, + nonce: Fr, + account: PublicKey, + ): Promise; + /** * Finds the nonce(s) for a note in a tx with given preimage at a specified contract address and storage slot. * @param contract - The contract address of the note. diff --git a/yarn-project/types/src/interfaces/nullifier_provider.ts b/yarn-project/types/src/interfaces/nullifier_provider.ts new file mode 100644 index 00000000000..4db85ce16f3 --- /dev/null +++ b/yarn-project/types/src/interfaces/nullifier_provider.ts @@ -0,0 +1,13 @@ +import { Fr } from '@aztec/foundation/fields'; + +/** + * Interface for providing information about nullifiers within the nullifier tree. + */ +export interface NullifierProvider { + /** + * Find the index of the given nullifier. + * @param nullifier - The nullifier to search for. + * @returns The index of the given leaf of undefined if not found. + */ + findNullifierIndex(nullifier: Fr): Promise; +}