@aztec/pxe 0.87.7 → 1.0.0-nightly.20250604

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dest/contract_function_simulator/execution_data_provider.d.ts +20 -16
  2. package/dest/contract_function_simulator/execution_data_provider.d.ts.map +1 -1
  3. package/dest/contract_function_simulator/note_validation_request.d.ts +21 -0
  4. package/dest/contract_function_simulator/note_validation_request.d.ts.map +1 -0
  5. package/dest/contract_function_simulator/note_validation_request.js +42 -0
  6. package/dest/contract_function_simulator/oracle/oracle.d.ts +3 -2
  7. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  8. package/dest/contract_function_simulator/oracle/oracle.js +21 -12
  9. package/dest/contract_function_simulator/oracle/typed_oracle.d.ts +4 -3
  10. package/dest/contract_function_simulator/oracle/typed_oracle.d.ts.map +1 -1
  11. package/dest/contract_function_simulator/oracle/typed_oracle.js +7 -4
  12. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +4 -3
  13. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  14. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +8 -5
  15. package/dest/contract_function_simulator/pxe_oracle_interface.d.ts +6 -4
  16. package/dest/contract_function_simulator/pxe_oracle_interface.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/pxe_oracle_interface.js +57 -21
  18. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
  19. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.js +30 -30
  20. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  21. package/dest/private_kernel/private_kernel_execution_prover.js +9 -7
  22. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  23. package/dest/pxe_service/pxe_service.js +10 -3
  24. package/dest/storage/capsule_data_provider/capsule_data_provider.d.ts +4 -2
  25. package/dest/storage/capsule_data_provider/capsule_data_provider.d.ts.map +1 -1
  26. package/dest/storage/capsule_data_provider/capsule_data_provider.js +46 -7
  27. package/dest/storage/note_data_provider/note_data_provider.d.ts.map +1 -1
  28. package/dest/storage/note_data_provider/note_data_provider.js +14 -14
  29. package/package.json +16 -16
  30. package/src/contract_function_simulator/execution_data_provider.ts +22 -26
  31. package/src/contract_function_simulator/note_validation_request.ts +52 -0
  32. package/src/contract_function_simulator/oracle/oracle.ts +24 -25
  33. package/src/contract_function_simulator/oracle/typed_oracle.ts +14 -14
  34. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +10 -24
  35. package/src/contract_function_simulator/pxe_oracle_interface.ts +98 -22
  36. package/src/private_kernel/hints/build_private_kernel_reset_private_inputs.ts +35 -34
  37. package/src/private_kernel/private_kernel_execution_prover.ts +11 -10
  38. package/src/pxe_service/pxe_service.ts +10 -3
  39. package/src/storage/capsule_data_provider/capsule_data_provider.ts +56 -7
  40. package/src/storage/note_data_provider/note_data_provider.ts +22 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/pxe",
3
- "version": "0.87.7",
3
+ "version": "1.0.0-nightly.20250604",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./server": "./dest/entrypoints/server/index.js",
@@ -58,19 +58,19 @@
58
58
  ]
59
59
  },
60
60
  "dependencies": {
61
- "@aztec/bb-prover": "0.87.7",
62
- "@aztec/bb.js": "0.87.7",
63
- "@aztec/builder": "0.87.7",
64
- "@aztec/constants": "0.87.7",
65
- "@aztec/ethereum": "0.87.7",
66
- "@aztec/foundation": "0.87.7",
67
- "@aztec/key-store": "0.87.7",
68
- "@aztec/kv-store": "0.87.7",
69
- "@aztec/noir-protocol-circuits-types": "0.87.7",
70
- "@aztec/noir-types": "0.87.7",
71
- "@aztec/protocol-contracts": "0.87.7",
72
- "@aztec/simulator": "0.87.7",
73
- "@aztec/stdlib": "0.87.7",
61
+ "@aztec/bb-prover": "1.0.0-nightly.20250604",
62
+ "@aztec/bb.js": "1.0.0-nightly.20250604",
63
+ "@aztec/builder": "1.0.0-nightly.20250604",
64
+ "@aztec/constants": "1.0.0-nightly.20250604",
65
+ "@aztec/ethereum": "1.0.0-nightly.20250604",
66
+ "@aztec/foundation": "1.0.0-nightly.20250604",
67
+ "@aztec/key-store": "1.0.0-nightly.20250604",
68
+ "@aztec/kv-store": "1.0.0-nightly.20250604",
69
+ "@aztec/noir-protocol-circuits-types": "1.0.0-nightly.20250604",
70
+ "@aztec/noir-types": "1.0.0-nightly.20250604",
71
+ "@aztec/protocol-contracts": "1.0.0-nightly.20250604",
72
+ "@aztec/simulator": "1.0.0-nightly.20250604",
73
+ "@aztec/stdlib": "1.0.0-nightly.20250604",
74
74
  "koa": "^2.16.1",
75
75
  "koa-router": "^12.0.0",
76
76
  "lodash.omit": "^4.5.0",
@@ -79,8 +79,8 @@
79
79
  "viem": "2.23.7"
80
80
  },
81
81
  "devDependencies": {
82
- "@aztec/merkle-tree": "0.87.7",
83
- "@aztec/noir-test-contracts.js": "0.87.7",
82
+ "@aztec/merkle-tree": "1.0.0-nightly.20250604",
83
+ "@aztec/noir-test-contracts.js": "1.0.0-nightly.20250604",
84
84
  "@jest/globals": "^29.5.0",
85
85
  "@types/jest": "^29.5.0",
86
86
  "@types/lodash.omit": "^4.5.7",
@@ -10,7 +10,7 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
10
10
  import type { L2Block } from '@aztec/stdlib/block';
11
11
  import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
12
12
  import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
13
- import { IndexedTaggingSecret, LogWithTxData } from '@aztec/stdlib/logs';
13
+ import { IndexedTaggingSecret, PrivateLogWithTxData, PublicLogWithTxData } from '@aztec/stdlib/logs';
14
14
  import type { NoteStatus } from '@aztec/stdlib/note';
15
15
  import { type MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
16
16
  import type { BlockHeader, NodeStats, TxHash } from '@aztec/stdlib/tx';
@@ -265,8 +265,8 @@ export interface ExecutionDataProvider {
265
265
  ): Promise<void>;
266
266
 
267
267
  /**
268
- * Synchronizes the logs tagged with scoped addresses and all the senders in the address book. Stores the found logs
269
- * in CapsuleArray ready for a later retrieval in Aztec.nr.
268
+ * Synchronizes the private logs tagged with scoped addresses and all the senders in the address book. Stores the found
269
+ * logs in CapsuleArray ready for a later retrieval in Aztec.nr.
270
270
  * @param contractAddress - The address of the contract that the logs are tagged for.
271
271
  * @param pendingTaggedLogArrayBaseSlot - The base slot of the pending tagged log capsule array in which found logs will be stored.
272
272
  * @param scopes - The scoped addresses to sync logs for. If not provided, all accounts in the address book will be
@@ -279,36 +279,32 @@ export interface ExecutionDataProvider {
279
279
  ): Promise<void>;
280
280
 
281
281
  /**
282
- * Delivers the preimage and metadata of a committed note so that it can be later requested via the `getNotes`
283
- * oracle.
284
- *
285
- * @param contractAddress - The address of the contract that created the note (i.e. the siloing contract)
286
- * @param storageSlot - The storage slot of the note - used for indexing in `getNotes`
287
- * @param nonce - The nonce of the note used by the kernel to compute the unique note hash
288
- * @param content - The note's content: this is the primary item to return in `getNotes`
289
- * @param noteHash - The non-unique non-siloed note hash
290
- * @param nullifier - The inner (non-siloed) note nullifier
291
- * @param txHash - The transaction in which the note was added to the note hash tree
292
- * @param recipient - The account that discovered the note
293
- */
294
- deliverNote(
295
- contractAddress: AztecAddress,
296
- storageSlot: Fr,
297
- nonce: Fr,
298
- content: Fr[],
299
- noteHash: Fr,
300
- nullifier: Fr,
301
- txHash: TxHash,
302
- recipient: AztecAddress,
303
- ): Promise<void>;
282
+ * Validates a capsule array of `NoteValidationRequests`, storing the notes in the database so that they can be later
283
+ * queried via `getNotes`.
284
+ * @param contractAddress - The contract that the notes belong to.
285
+ * @param noteValidationRequestArrayBaseSlot - The capsule array base slot.
286
+ */
287
+ validateEnqueuedNotes(contractAddress: AztecAddress, noteValidationRequestArrayBaseSlot: Fr): Promise<void>;
304
288
 
305
289
  /**
306
290
  * Searches for a log with the corresponding `tag` and returns it along with contextual transaction information.
307
291
  * Returns null if no such log exists, and throws if more than one exists.
308
292
  *
309
293
  * @param tag - The log tag to search for.
294
+ * @param contractAddress - The contract address to search for the log in.
295
+ * @returns The public log with transaction data if found, null otherwise.
296
+ * @throws If more than one log with that tag exists.
297
+ */
298
+ getPublicLogByTag(tag: Fr, contractAddress: AztecAddress): Promise<PublicLogWithTxData | null>;
299
+
300
+ /**
301
+ * Searches for a private log with the corresponding `siloedTag` and returns it along with contextual transaction
302
+ * information.
303
+ *
304
+ * @param siloedTag - The siloed log tag to search for.
305
+ * @returns The private log with transaction data if found, null otherwise.
310
306
  */
311
- getLogByTag(tag: Fr): Promise<LogWithTxData | null>;
307
+ getPrivateLogByTag(siloedTag: Fr): Promise<PrivateLogWithTxData | null>;
312
308
 
313
309
  /**
314
310
  * Removes all of a contract's notes that have been nullified from the note database.
@@ -0,0 +1,52 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import { FieldReader } from '@aztec/foundation/serialize';
3
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import { TxHash } from '@aztec/stdlib/tx';
5
+
6
+ // TODO(#14617): should we compute this from constants? This value is aztec-nr specific.
7
+ const MAX_NOTE_PACKED_LEN = 12;
8
+
9
+ /**
10
+ * Intermediate struct used to perform batch note validation by PXE. The `validateEnqueuedNotes` oracle expects for
11
+ * values of this type to be stored in a `CapsuleArray`.
12
+ */
13
+ export class NoteValidationRequest {
14
+ constructor(
15
+ public contractAddress: AztecAddress,
16
+ public storageSlot: Fr,
17
+ public nonce: Fr,
18
+ public content: Fr[],
19
+ public noteHash: Fr,
20
+ public nullifier: Fr,
21
+ public txHash: TxHash,
22
+ public recipient: AztecAddress,
23
+ ) {}
24
+
25
+ static fromFields(fields: Fr[] | FieldReader): NoteValidationRequest {
26
+ const reader = FieldReader.asReader(fields);
27
+
28
+ const contractAddress = AztecAddress.fromField(reader.readField());
29
+ const storageSlot = reader.readField();
30
+ const nonce = reader.readField();
31
+
32
+ const contentStorage = reader.readFieldArray(MAX_NOTE_PACKED_LEN);
33
+ const contentLen = reader.readField().toNumber();
34
+ const content = contentStorage.slice(0, contentLen);
35
+
36
+ const noteHash = reader.readField();
37
+ const nullifier = reader.readField();
38
+ const txHash = TxHash.fromField(reader.readField());
39
+ const recipient = AztecAddress.fromField(reader.readField());
40
+
41
+ return new NoteValidationRequest(
42
+ contractAddress,
43
+ storageSlot,
44
+ nonce,
45
+ content,
46
+ noteHash,
47
+ nullifier,
48
+ txHash,
49
+ recipient,
50
+ );
51
+ }
52
+ }
@@ -12,7 +12,12 @@ import {
12
12
  } from '@aztec/simulator/client';
13
13
  import { EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
14
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
15
- import { ContractClassLog, ContractClassLogFields, LogWithTxData } from '@aztec/stdlib/logs';
15
+ import {
16
+ ContractClassLog,
17
+ ContractClassLogFields,
18
+ PrivateLogWithTxData,
19
+ PublicLogWithTxData,
20
+ } from '@aztec/stdlib/logs';
16
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
17
22
  import { TxHash } from '@aztec/stdlib/tx';
18
23
 
@@ -402,39 +407,33 @@ export class Oracle {
402
407
  return [];
403
408
  }
404
409
 
405
- async deliverNote(
410
+ async validateEnqueuedNotes(
406
411
  [contractAddress]: ACVMField[],
407
- [storageSlot]: ACVMField[],
408
- [nonce]: ACVMField[],
409
- content: ACVMField[],
410
- [contentLength]: ACVMField[],
411
- [noteHash]: ACVMField[],
412
- [nullifier]: ACVMField[],
413
- [txHash]: ACVMField[],
414
- [recipient]: ACVMField[],
412
+ [noteValidationRequestsArrayBaseSlot]: ACVMField[],
415
413
  ): Promise<ACVMField[]> {
416
- // TODO(#10728): try-catch this block and return false if we get an exception so that the contract can decide what
417
- // to do if a note fails delivery (e.g. not increment the tagging index, or add it to some pending work list).
418
- // Delivery might fail due to temporary issues, such as poor node connectivity.
419
- await this.typedOracle.deliverNote(
414
+ await this.typedOracle.validateEnqueuedNotes(
420
415
  AztecAddress.fromString(contractAddress),
421
- Fr.fromString(storageSlot),
422
- Fr.fromString(nonce),
423
- fromBoundedVec(content, contentLength),
424
- Fr.fromString(noteHash),
425
- Fr.fromString(nullifier),
426
- TxHash.fromString(txHash),
427
- AztecAddress.fromString(recipient),
416
+ Fr.fromString(noteValidationRequestsArrayBaseSlot),
428
417
  );
429
418
 
430
- return [toACVMField(true)];
419
+ return [];
420
+ }
421
+
422
+ async getPublicLogByTag([tag]: ACVMField[], [contractAddress]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> {
423
+ const log = await this.typedOracle.getPublicLogByTag(Fr.fromString(tag), AztecAddress.fromString(contractAddress));
424
+
425
+ if (log == null) {
426
+ return [toACVMField(0), ...PublicLogWithTxData.noirSerializationOfEmpty().map(toACVMFieldSingleOrArray)];
427
+ } else {
428
+ return [toACVMField(1), ...log.toNoirSerialization().map(toACVMFieldSingleOrArray)];
429
+ }
431
430
  }
432
431
 
433
- async getLogByTag([tag]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> {
434
- const log = await this.typedOracle.getLogByTag(Fr.fromString(tag));
432
+ async getPrivateLogByTag([siloedTag]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> {
433
+ const log = await this.typedOracle.getPrivateLogByTag(Fr.fromString(siloedTag));
435
434
 
436
435
  if (log == null) {
437
- return [toACVMField(0), ...LogWithTxData.noirSerializationOfEmpty().map(toACVMFieldSingleOrArray)];
436
+ return [toACVMField(0), ...PrivateLogWithTxData.noirSerializationOfEmpty().map(toACVMFieldSingleOrArray)];
438
437
  } else {
439
438
  return [toACVMField(1), ...log.toNoirSerialization().map(toACVMFieldSingleOrArray)];
440
439
  }
@@ -4,7 +4,12 @@ import type { EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdli
4
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
5
  import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
6
6
  import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
7
- import type { ContractClassLog, IndexedTaggingSecret, LogWithTxData } from '@aztec/stdlib/logs';
7
+ import type {
8
+ ContractClassLog,
9
+ IndexedTaggingSecret,
10
+ PrivateLogWithTxData,
11
+ PublicLogWithTxData,
12
+ } from '@aztec/stdlib/logs';
8
13
  import type { Note, NoteStatus } from '@aztec/stdlib/note';
9
14
  import { type MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
10
15
  import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
@@ -218,21 +223,16 @@ export abstract class TypedOracle {
218
223
  return Promise.reject(new OracleMethodNotAvailableError('fetchTaggedLogs'));
219
224
  }
220
225
 
221
- deliverNote(
222
- _contractAddress: AztecAddress,
223
- _storageSlot: Fr,
224
- _nonce: Fr,
225
- _content: Fr[],
226
- _noteHash: Fr,
227
- _nullifier: Fr,
228
- _txHash: TxHash,
229
- _recipient: AztecAddress,
230
- ): Promise<void> {
231
- return Promise.reject(new OracleMethodNotAvailableError('deliverNote'));
226
+ validateEnqueuedNotes(_contractAddress: AztecAddress, _noteValidationRequestsArrayBaseSlot: Fr): Promise<void> {
227
+ return Promise.reject(new OracleMethodNotAvailableError('validateEnqueuedNotes'));
228
+ }
229
+
230
+ getPublicLogByTag(_tag: Fr, _contractAddress: AztecAddress): Promise<PublicLogWithTxData | null> {
231
+ throw new OracleMethodNotAvailableError('getPublicLogByTag');
232
232
  }
233
233
 
234
- getLogByTag(_tag: Fr): Promise<LogWithTxData | null> {
235
- throw new OracleMethodNotAvailableError('getLogByTag');
234
+ getPrivateLogByTag(_siloedTag: Fr): Promise<PrivateLogWithTxData | null> {
235
+ throw new OracleMethodNotAvailableError('getPrivateLogByTag');
236
236
  }
237
237
 
238
238
  storeCapsule(_contractAddress: AztecAddress, _key: Fr, _capsule: Fr[]): Promise<void> {
@@ -7,7 +7,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
7
7
  import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
8
8
  import { siloNullifier } from '@aztec/stdlib/hash';
9
9
  import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
10
- import { IndexedTaggingSecret, LogWithTxData } from '@aztec/stdlib/logs';
10
+ import { IndexedTaggingSecret, PrivateLogWithTxData, PublicLogWithTxData } from '@aztec/stdlib/logs';
11
11
  import type { NoteStatus } from '@aztec/stdlib/note';
12
12
  import { type MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
13
13
  import type { BlockHeader, Capsule, TxHash } from '@aztec/stdlib/tx';
@@ -280,35 +280,21 @@ export class UtilityExecutionOracle extends TypedOracle {
280
280
  await this.executionDataProvider.removeNullifiedNotes(this.contractAddress);
281
281
  }
282
282
 
283
- public override async deliverNote(
284
- contractAddress: AztecAddress,
285
- storageSlot: Fr,
286
- nonce: Fr,
287
- content: Fr[],
288
- noteHash: Fr,
289
- nullifier: Fr,
290
- txHash: TxHash,
291
- recipient: AztecAddress,
292
- ) {
283
+ public override async validateEnqueuedNotes(contractAddress: AztecAddress, noteValidationRequestsArrayBaseSlot: Fr) {
293
284
  // TODO(#10727): allow other contracts to deliver notes
294
285
  if (!this.contractAddress.equals(contractAddress)) {
295
- throw new Error(`Got a note delivery request from ${contractAddress}, expected ${this.contractAddress}`);
286
+ throw new Error(`Got a note validation request from ${contractAddress}, expected ${this.contractAddress}`);
296
287
  }
297
288
 
298
- await this.executionDataProvider.deliverNote(
299
- contractAddress,
300
- storageSlot,
301
- nonce,
302
- content,
303
- noteHash,
304
- nullifier,
305
- txHash,
306
- recipient,
307
- );
289
+ await this.executionDataProvider.validateEnqueuedNotes(contractAddress, noteValidationRequestsArrayBaseSlot);
290
+ }
291
+
292
+ public override getPublicLogByTag(tag: Fr, contractAddress: AztecAddress): Promise<PublicLogWithTxData | null> {
293
+ return this.executionDataProvider.getPublicLogByTag(tag, contractAddress);
308
294
  }
309
295
 
310
- public override getLogByTag(tag: Fr): Promise<LogWithTxData | null> {
311
- return this.executionDataProvider.getLogByTag(tag);
296
+ public override getPrivateLogByTag(siloedTag: Fr): Promise<PrivateLogWithTxData | null> {
297
+ return this.executionDataProvider.getPrivateLogByTag(siloedTag);
312
298
  }
313
299
 
314
300
  public override storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
@@ -18,9 +18,10 @@ import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
18
18
  import { computeAddressSecret, computeAppTaggingSecret } from '@aztec/stdlib/keys';
19
19
  import {
20
20
  IndexedTaggingSecret,
21
- LogWithTxData,
22
21
  PendingTaggedLog,
22
+ PrivateLogWithTxData,
23
23
  PublicLog,
24
+ PublicLogWithTxData,
24
25
  TxScopedL2Log,
25
26
  deriveEcdhSharedSecret,
26
27
  } from '@aztec/stdlib/logs';
@@ -40,6 +41,7 @@ import type { NoteDataProvider } from '../storage/note_data_provider/note_data_p
40
41
  import type { PrivateEventDataProvider } from '../storage/private_event_data_provider/private_event_data_provider.js';
41
42
  import type { SyncDataProvider } from '../storage/sync_data_provider/sync_data_provider.js';
42
43
  import type { TaggingDataProvider } from '../storage/tagging_data_provider/tagging_data_provider.js';
44
+ import { NoteValidationRequest } from './note_validation_request.js';
43
45
  import type { ProxiedNode } from './proxied_node.js';
44
46
  import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
45
47
 
@@ -384,7 +386,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
384
386
  });
385
387
 
386
388
  // We fetch the logs for the tags
387
- const possibleLogs = await this.aztecNode.getLogsByTags(currentTags);
389
+ const possibleLogs = await this.#getPrivateLogsByTags(currentTags);
388
390
 
389
391
  // We find the index of the last log in the window that is not empty
390
392
  const indexOfLastLog = possibleLogs.findLastIndex(possibleLog => possibleLog.length !== 0);
@@ -421,8 +423,8 @@ export class PXEOracleInterface implements ExecutionDataProvider {
421
423
  }
422
424
 
423
425
  /**
424
- * Synchronizes the logs tagged with scoped addresses and all the senders in the address book. Stores the found logs
425
- * in CapsuleArray ready for a later retrieval in Aztec.nr.
426
+ * Synchronizes the private logs tagged with scoped addresses and all the senders in the address book. Stores the found
427
+ * logs in CapsuleArray ready for a later retrieval in Aztec.nr.
426
428
  * @param contractAddress - The address of the contract that the logs are tagged for.
427
429
  * @param pendingTaggedLogArrayBaseSlot - The base slot of the pending tagged logs capsule array in which
428
430
  * found logs will be stored.
@@ -482,20 +484,14 @@ export class PXEOracleInterface implements ExecutionDataProvider {
482
484
  // a new set of secrets and windows to fetch logs for.
483
485
  const newLargestIndexMapForIteration: { [k: string]: number } = {};
484
486
 
485
- // Fetch the logs for the tags and iterate over them
486
- const logsByTags = await this.aztecNode.getLogsByTags(tagsForTheWholeWindow);
487
+ // Fetch the private logs for the tags and iterate over them
488
+ const logsByTags = await this.#getPrivateLogsByTags(tagsForTheWholeWindow);
487
489
 
488
490
  for (let logIndex = 0; logIndex < logsByTags.length; logIndex++) {
489
491
  const logsByTag = logsByTags[logIndex];
490
492
  if (logsByTag.length > 0) {
491
- // Discard public logs
492
- const filteredLogsByTag = logsByTag.filter(l => !l.isFromPublic);
493
- if (filteredLogsByTag.length < logsByTag.length) {
494
- this.log.warn(`Discarded ${logsByTag.filter(l => l.isFromPublic).length} public logs with matching tags`);
495
- }
496
-
497
493
  // We filter out the logs that are newer than the historical block number of the tx currently being constructed
498
- const filteredLogsByBlockNumber = filteredLogsByTag.filter(l => l.blockNumber <= maxBlockNumber);
494
+ const filteredLogsByBlockNumber = logsByTag.filter(l => l.blockNumber <= maxBlockNumber);
499
495
 
500
496
  // We store the logs in capsules (to later be obtained in Noir)
501
497
  await this.#storePendingTaggedLogs(
@@ -510,7 +506,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
510
506
  const secretCorrespondingToLog = secretsForTheWholeWindow[logIndex];
511
507
  const initialIndex = initialIndexesMap[secretCorrespondingToLog.appTaggingSecret.toString()];
512
508
 
513
- this.log.debug(`Found ${filteredLogsByTag.length} logs as recipient ${recipient}`, {
509
+ this.log.debug(`Found ${logsByTags.length} logs as recipient ${recipient}`, {
514
510
  recipient,
515
511
  secret: secretCorrespondingToLog.appTaggingSecret,
516
512
  contractName,
@@ -606,7 +602,36 @@ export class PXEOracleInterface implements ExecutionDataProvider {
606
602
  return this.capsuleDataProvider.appendToCapsuleArray(contractAddress, capsuleArrayBaseSlot, pendingTaggedLogs);
607
603
  }
608
604
 
609
- public async deliverNote(
605
+ public async validateEnqueuedNotes(
606
+ contractAddress: AztecAddress,
607
+ noteValidationRequestsArrayBaseSlot: Fr,
608
+ ): Promise<void> {
609
+ // We read all note validation requests and process them all concurrently. This makes the process much faster as we
610
+ // don't need to wait for the network round-trip.
611
+ const noteValidationRequests = (
612
+ await this.capsuleDataProvider.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot)
613
+ ).map(NoteValidationRequest.fromFields);
614
+
615
+ await Promise.all(
616
+ noteValidationRequests.map(request =>
617
+ this.deliverNote(
618
+ request.contractAddress,
619
+ request.storageSlot,
620
+ request.nonce,
621
+ request.content,
622
+ request.noteHash,
623
+ request.nullifier,
624
+ request.txHash,
625
+ request.recipient,
626
+ ),
627
+ ),
628
+ );
629
+
630
+ // Requests are cleared once we're done.
631
+ await this.capsuleDataProvider.resetCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, []);
632
+ }
633
+
634
+ async deliverNote(
610
635
  contractAddress: AztecAddress,
611
636
  storageSlot: Fr,
612
637
  nonce: Fr,
@@ -690,18 +715,18 @@ export class PXEOracleInterface implements ExecutionDataProvider {
690
715
  }
691
716
  }
692
717
 
693
- public async getLogByTag(tag: Fr): Promise<LogWithTxData | null> {
694
- const logs = await this.aztecNode.getLogsByTags([tag]);
718
+ public async getPublicLogByTag(tag: Fr, contractAddress: AztecAddress): Promise<PublicLogWithTxData | null> {
719
+ const logs = await this.#getPublicLogsByTagsFromContract([tag], contractAddress);
695
720
  const logsForTag = logs[0];
696
721
 
697
- this.log.debug(`Got ${logsForTag.length} logs for tag ${tag}`);
722
+ this.log.debug(`Got ${logsForTag.length} public logs for tag ${tag}`);
698
723
 
699
724
  if (logsForTag.length == 0) {
700
725
  return null;
701
726
  } else if (logsForTag.length > 1) {
702
727
  // TODO(#11627): handle this case
703
728
  throw new Error(
704
- `Got ${logsForTag.length} logs for tag ${tag}. getLogByTag currently only supports a single log per tag`,
729
+ `Got ${logsForTag.length} logs for tag ${tag} and contract ${contractAddress.toString()}. getPublicLogByTag currently only supports a single log per tag`,
705
730
  );
706
731
  }
707
732
 
@@ -715,11 +740,45 @@ export class PXEOracleInterface implements ExecutionDataProvider {
715
740
  throw new Error(`Unexpected: failed to retrieve tx effects for tx ${scopedLog.txHash} which is known to exist`);
716
741
  }
717
742
 
718
- const logContent = (scopedLog.isFromPublic ? [(scopedLog.log as PublicLog).contractAddress.toField()] : []).concat(
719
- scopedLog.log.getEmittedFields(),
743
+ return new PublicLogWithTxData(
744
+ scopedLog.log.getEmittedFieldsWithoutTag(),
745
+ scopedLog.txHash,
746
+ txEffect.data.noteHashes,
747
+ txEffect.data.nullifiers[0],
720
748
  );
749
+ }
750
+
751
+ public async getPrivateLogByTag(siloedTag: Fr): Promise<PrivateLogWithTxData | null> {
752
+ const logs = await this.#getPrivateLogsByTags([siloedTag]);
753
+ const logsForTag = logs[0];
754
+
755
+ this.log.debug(`Got ${logsForTag.length} private logs for tag ${siloedTag}`);
756
+
757
+ if (logsForTag.length == 0) {
758
+ return null;
759
+ } else if (logsForTag.length > 1) {
760
+ // TODO(#11627): handle this case
761
+ throw new Error(
762
+ `Got ${logsForTag.length} logs for tag ${siloedTag}. getPrivateLogByTag currently only supports a single log per tag`,
763
+ );
764
+ }
765
+
766
+ const scopedLog = logsForTag[0];
721
767
 
722
- return new LogWithTxData(logContent, scopedLog.txHash, txEffect.data.noteHashes, txEffect.data.nullifiers[0]);
768
+ // getLogsByTag doesn't have all of the information that we need (notably note hashes and the first nullifier), so
769
+ // we need to make a second call to the node for `getTxEffect`.
770
+ // TODO(#9789): bundle this information in the `getLogsByTag` call.
771
+ const txEffect = await this.aztecNode.getTxEffect(scopedLog.txHash);
772
+ if (txEffect == undefined) {
773
+ throw new Error(`Unexpected: failed to retrieve tx effects for tx ${scopedLog.txHash} which is known to exist`);
774
+ }
775
+
776
+ return new PrivateLogWithTxData(
777
+ scopedLog.log.getEmittedFieldsWithoutTag(),
778
+ scopedLog.txHash,
779
+ txEffect.data.noteHashes,
780
+ txEffect.data.nullifiers[0],
781
+ );
723
782
  }
724
783
 
725
784
  public async removeNullifiedNotes(contractAddress: AztecAddress) {
@@ -823,6 +882,23 @@ export class PXEOracleInterface implements ExecutionDataProvider {
823
882
  );
824
883
  }
825
884
 
885
+ // TODO(#12656): Make this a public function on the AztecNode interface and remove the original getLogsByTags. This
886
+ // was not done yet as we were unsure about the API and we didn't want to introduce a breaking change.
887
+ async #getPrivateLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
888
+ const allLogs = await this.aztecNode.getLogsByTags(tags);
889
+ return allLogs.map(logs => logs.filter(log => !log.isFromPublic));
890
+ }
891
+
892
+ // TODO(#12656): Make this a public function on the AztecNode interface and remove the original getLogsByTags. This
893
+ // was not done yet as we were unsure about the API and we didn't want to introduce a breaking change.
894
+ async #getPublicLogsByTagsFromContract(tags: Fr[], contractAddress: AztecAddress): Promise<TxScopedL2Log[][]> {
895
+ const allLogs = await this.aztecNode.getLogsByTags(tags);
896
+ const allPublicLogs = allLogs.map(logs => logs.filter(log => log.isFromPublic));
897
+ return allPublicLogs.map(logs =>
898
+ logs.filter(log => (log.log as PublicLog).contractAddress.equals(contractAddress)),
899
+ );
900
+ }
901
+
826
902
  getStats(): ExecutionStats {
827
903
  const nodeRPCCalls =
828
904
  typeof (this.aztecNode as ProxiedNode).getStats === 'function' ? (this.aztecNode as ProxiedNode).getStats() : {};