@aztec/pxe 0.0.1-commit.9ee6fcc6 → 0.0.1-commit.9ef841308

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 (92) hide show
  1. package/dest/block_synchronizer/block_synchronizer.d.ts +1 -1
  2. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.js +6 -0
  4. package/dest/contract_function_simulator/contract_function_simulator.d.ts +1 -1
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/contract_function_simulator.js +4 -3
  7. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +2 -3
  8. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +2 -5
  10. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +2 -3
  11. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +2 -5
  13. package/dest/contract_function_simulator/oracle/interfaces.d.ts +19 -19
  14. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +1 -1
  16. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +18 -22
  18. package/dest/contract_function_simulator/oracle/oracle.d.ts +38 -19
  19. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  20. package/dest/contract_function_simulator/oracle/oracle.js +60 -39
  21. package/dest/contract_function_simulator/oracle/private_execution.js +1 -1
  22. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +6 -6
  23. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  24. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +7 -7
  25. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +28 -26
  26. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  27. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +108 -69
  28. package/dest/contract_logging.d.ts +9 -4
  29. package/dest/contract_logging.d.ts.map +1 -1
  30. package/dest/contract_logging.js +21 -6
  31. package/dest/contract_sync/contract_sync_service.d.ts +3 -2
  32. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  33. package/dest/contract_sync/contract_sync_service.js +12 -2
  34. package/dest/contract_sync/helpers.d.ts +2 -2
  35. package/dest/contract_sync/helpers.d.ts.map +1 -1
  36. package/dest/contract_sync/helpers.js +7 -2
  37. package/dest/events/event_service.d.ts +3 -2
  38. package/dest/events/event_service.d.ts.map +1 -1
  39. package/dest/events/event_service.js +16 -4
  40. package/dest/logs/log_service.d.ts +6 -7
  41. package/dest/logs/log_service.d.ts.map +1 -1
  42. package/dest/logs/log_service.js +24 -28
  43. package/dest/messages/message_context_service.d.ts +3 -3
  44. package/dest/messages/message_context_service.d.ts.map +1 -1
  45. package/dest/messages/message_context_service.js +3 -3
  46. package/dest/notes/note_service.d.ts +2 -2
  47. package/dest/notes/note_service.d.ts.map +1 -1
  48. package/dest/notes/note_service.js +14 -5
  49. package/dest/oracle_version.d.ts +2 -2
  50. package/dest/oracle_version.js +2 -2
  51. package/dest/pxe.d.ts +1 -1
  52. package/dest/pxe.d.ts.map +1 -1
  53. package/dest/pxe.js +4 -2
  54. package/dest/storage/capsule_store/capsule_service.d.ts +22 -0
  55. package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -0
  56. package/dest/storage/capsule_store/capsule_service.js +50 -0
  57. package/dest/storage/capsule_store/capsule_store.d.ts +9 -9
  58. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  59. package/dest/storage/capsule_store/capsule_store.js +33 -28
  60. package/dest/storage/capsule_store/index.d.ts +2 -1
  61. package/dest/storage/capsule_store/index.d.ts.map +1 -1
  62. package/dest/storage/capsule_store/index.js +1 -0
  63. package/dest/storage/metadata.d.ts +1 -1
  64. package/dest/storage/metadata.js +1 -1
  65. package/package.json +16 -16
  66. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  67. package/src/contract_function_simulator/contract_function_simulator.ts +4 -3
  68. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +0 -3
  69. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +0 -3
  70. package/src/contract_function_simulator/oracle/interfaces.ts +26 -17
  71. package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +13 -50
  72. package/src/contract_function_simulator/oracle/oracle.ts +79 -33
  73. package/src/contract_function_simulator/oracle/private_execution.ts +1 -1
  74. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +7 -7
  75. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +195 -78
  76. package/src/contract_logging.ts +18 -5
  77. package/src/contract_sync/contract_sync_service.ts +22 -11
  78. package/src/contract_sync/helpers.ts +3 -2
  79. package/src/events/event_service.ts +17 -4
  80. package/src/logs/log_service.ts +51 -46
  81. package/src/messages/message_context_service.ts +3 -4
  82. package/src/notes/note_service.ts +16 -5
  83. package/src/oracle_version.ts +2 -2
  84. package/src/pxe.ts +4 -1
  85. package/src/storage/capsule_store/capsule_service.ts +91 -0
  86. package/src/storage/capsule_store/capsule_store.ts +34 -26
  87. package/src/storage/capsule_store/index.ts +1 -0
  88. package/src/storage/metadata.ts +1 -1
  89. package/dest/contract_function_simulator/noir-structs/message_tx_context.d.ts +0 -16
  90. package/dest/contract_function_simulator/noir-structs/message_tx_context.d.ts.map +0 -1
  91. package/dest/contract_function_simulator/noir-structs/message_tx_context.js +0 -57
  92. package/src/contract_function_simulator/noir-structs/message_tx_context.ts +0 -55
@@ -15,14 +15,14 @@ import { siloNullifier } from '@aztec/stdlib/hash';
15
15
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
16
16
  import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
17
17
  import { type PublicKeys, computeAddressSecret } from '@aztec/stdlib/keys';
18
- import { deriveEcdhSharedSecret } from '@aztec/stdlib/logs';
18
+ import { MessageContext, deriveAppSiloedSharedSecret } from '@aztec/stdlib/logs';
19
19
  import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
20
20
  import type { NoteStatus } from '@aztec/stdlib/note';
21
21
  import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
22
22
  import type { BlockHeader, Capsule, OffchainEffect } from '@aztec/stdlib/tx';
23
23
 
24
24
  import type { AccessScopes } from '../../access_scopes.js';
25
- import { createContractLogger, logContractMessage } from '../../contract_logging.js';
25
+ import { createContractLogger, logContractMessage, stripAztecnrLogPrefix } from '../../contract_logging.js';
26
26
  import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
27
27
  import { EventService } from '../../events/event_service.js';
28
28
  import { LogService } from '../../logs/log_service.js';
@@ -30,7 +30,7 @@ import { MessageContextService } from '../../messages/message_context_service.js
30
30
  import { NoteService } from '../../notes/note_service.js';
31
31
  import { ORACLE_VERSION } from '../../oracle_version.js';
32
32
  import type { AddressStore } from '../../storage/address_store/address_store.js';
33
- import type { CapsuleStore } from '../../storage/capsule_store/capsule_store.js';
33
+ import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
34
34
  import type { ContractStore } from '../../storage/contract_store/contract_store.js';
35
35
  import type { NoteStore } from '../../storage/note_store/note_store.js';
36
36
  import type { PrivateEventStore } from '../../storage/private_event_store/private_event_store.js';
@@ -39,7 +39,6 @@ import type { SenderAddressBookStore } from '../../storage/tagging_store/sender_
39
39
  import { EventValidationRequest } from '../noir-structs/event_validation_request.js';
40
40
  import { LogRetrievalRequest } from '../noir-structs/log_retrieval_request.js';
41
41
  import { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
42
- import { MessageTxContext } from '../noir-structs/message_tx_context.js';
43
42
  import { NoteValidationRequest } from '../noir-structs/note_validation_request.js';
44
43
  import { UtilityContext } from '../noir-structs/utility_context.js';
45
44
  import { pickNotes } from '../pick_notes.js';
@@ -60,7 +59,7 @@ export type UtilityExecutionOracleArgs = {
60
59
  aztecNode: AztecNode;
61
60
  recipientTaggingStore: RecipientTaggingStore;
62
61
  senderAddressBookStore: SenderAddressBookStore;
63
- capsuleStore: CapsuleStore;
62
+ capsuleService: CapsuleService;
64
63
  privateEventStore: PrivateEventStore;
65
64
  messageContextService: MessageContextService;
66
65
  contractSyncService: ContractSyncService;
@@ -77,6 +76,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
77
76
  isUtility = true as const;
78
77
 
79
78
  private contractLogger: Logger | undefined;
79
+ private aztecnrLogger: Logger | undefined;
80
80
  private offchainEffects: OffchainEffect[] = [];
81
81
 
82
82
  protected readonly contractAddress: AztecAddress;
@@ -90,7 +90,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
90
90
  protected readonly aztecNode: AztecNode;
91
91
  protected readonly recipientTaggingStore: RecipientTaggingStore;
92
92
  protected readonly senderAddressBookStore: SenderAddressBookStore;
93
- protected readonly capsuleStore: CapsuleStore;
93
+ protected readonly capsuleService: CapsuleService;
94
94
  protected readonly privateEventStore: PrivateEventStore;
95
95
  protected readonly messageContextService: MessageContextService;
96
96
  protected readonly contractSyncService: ContractSyncService;
@@ -110,7 +110,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
110
110
  this.aztecNode = args.aztecNode;
111
111
  this.recipientTaggingStore = args.recipientTaggingStore;
112
112
  this.senderAddressBookStore = args.senderAddressBookStore;
113
- this.capsuleStore = args.capsuleStore;
113
+ this.capsuleService = args.capsuleService;
114
114
  this.privateEventStore = args.privateEventStore;
115
115
  this.messageContextService = args.messageContextService;
116
116
  this.contractSyncService = args.contractSyncService;
@@ -128,15 +128,25 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
128
128
  const LEGACY_ORACLE_VERSION = 12;
129
129
  if (isProtocolContract(this.contractAddress)) {
130
130
  if (version !== LEGACY_ORACLE_VERSION && version !== ORACLE_VERSION) {
131
+ const hint =
132
+ version > ORACLE_VERSION
133
+ ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
134
+ : 'The contract was compiled with an older version of Aztec.nr than your private environment supports. Recompile the contract with a compatible version of Aztec.nr.';
131
135
  throw new Error(
132
- `Expected legacy oracle version ${LEGACY_ORACLE_VERSION} or current oracle version ${ORACLE_VERSION} for alpha payload contract at ${this.contractAddress}, got ${version}.`,
136
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle version ${LEGACY_ORACLE_VERSION} or ${ORACLE_VERSION}, got ${version})`,
133
137
  );
134
138
  }
135
139
  return;
136
140
  }
137
141
 
138
142
  if (version !== ORACLE_VERSION) {
139
- throw new Error(`Incompatible oracle version. Expected version ${ORACLE_VERSION}, got ${version}.`);
143
+ const hint =
144
+ version > ORACLE_VERSION
145
+ ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
146
+ : 'The contract was compiled with an older version of Aztec.nr than your private environment supports. Recompile the contract with a compatible version of Aztec.nr.';
147
+ throw new Error(
148
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle version ${ORACLE_VERSION}, got ${version})`,
149
+ );
140
150
  }
141
151
  }
142
152
 
@@ -173,16 +183,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
173
183
 
174
184
  /**
175
185
  * Fetches the index and sibling path of a leaf at a given block from the note hash tree.
176
- * @param anchorBlockHash - The hash of a block that contains the note hash tree root in which to find the membership
177
- * witness.
186
+ * @param blockHash - The hash of a block that contains the note hash tree root in which to find the
187
+ * membership witness.
178
188
  * @param noteHash - The note hash to find in the note hash tree.
179
189
  * @returns The membership witness containing the leaf index and sibling path
180
190
  */
181
191
  public getNoteHashMembershipWitness(
182
- anchorBlockHash: BlockHash,
192
+ blockHash: BlockHash,
183
193
  noteHash: Fr,
184
194
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
185
- return this.aztecNode.getNoteHashMembershipWitness(anchorBlockHash, noteHash);
195
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
196
+ this.aztecNode.getNoteHashMembershipWitness(blockHash, noteHash),
197
+ );
186
198
  }
187
199
 
188
200
  /**
@@ -191,16 +203,21 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
191
203
  * Block hashes are the leaves of the archive tree. Each time a new block is added to the chain,
192
204
  * its block hash is appended as a new leaf to the archive tree.
193
205
  *
194
- * @param anchorBlockHash - The hash of a block that contains the archive tree root in which to find the membership
206
+ * @param referenceBlockHash - The hash of a block that contains the archive tree root in which to find the membership
195
207
  * witness.
196
208
  * @param blockHash - The block hash to find in the archive tree.
197
209
  * @returns The membership witness containing the leaf index and sibling path
198
210
  */
199
211
  public getBlockHashMembershipWitness(
200
- anchorBlockHash: BlockHash,
212
+ referenceBlockHash: BlockHash,
201
213
  blockHash: BlockHash,
202
214
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
203
- return this.aztecNode.getBlockHashMembershipWitness(anchorBlockHash, blockHash);
215
+ // Note that we validate that the reference block hash is at or before the anchor block - we don't test the block
216
+ // hash at all. If the block hash did not exist by the reference block hash, then the node will not return the
217
+ // membership witness as there is none.
218
+ return this.#queryWithBlockHashNotAfterAnchor(referenceBlockHash, () =>
219
+ this.aztecNode.getBlockHashMembershipWitness(referenceBlockHash, blockHash),
220
+ );
204
221
  }
205
222
 
206
223
  /**
@@ -213,7 +230,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
213
230
  blockHash: BlockHash,
214
231
  nullifier: Fr,
215
232
  ): Promise<NullifierMembershipWitness | undefined> {
216
- return this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier);
233
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
234
+ this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier),
235
+ );
217
236
  }
218
237
 
219
238
  /**
@@ -229,7 +248,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
229
248
  blockHash: BlockHash,
230
249
  nullifier: Fr,
231
250
  ): Promise<NullifierMembershipWitness | undefined> {
232
- return this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier);
251
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
252
+ this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier),
253
+ );
233
254
  }
234
255
 
235
256
  /**
@@ -239,7 +260,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
239
260
  * @returns - The witness
240
261
  */
241
262
  public getPublicDataWitness(blockHash: BlockHash, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
242
- return this.aztecNode.getPublicDataWitness(blockHash, leafSlot);
263
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
264
+ this.aztecNode.getPublicDataWitness(blockHash, leafSlot),
265
+ );
243
266
  }
244
267
 
245
268
  /**
@@ -262,7 +285,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
262
285
  * @param account - The account address.
263
286
  * @returns The public keys and partial address, or `undefined` if the account is not registered.
264
287
  */
265
- public async tryGetPublicKeysAndPartialAddress(
288
+ public async getPublicKeysAndPartialAddress(
266
289
  account: AztecAddress,
267
290
  ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> {
268
291
  const completeAddress = await this.addressStore.getCompleteAddress(account);
@@ -368,7 +391,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
368
391
  * @param innerNullifier - The inner nullifier.
369
392
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
370
393
  */
371
- public async checkNullifierExists(innerNullifier: Fr) {
394
+ public async doesNullifierExist(innerNullifier: Fr) {
372
395
  const [nullifier, anchorBlockHash] = await Promise.all([
373
396
  siloNullifier(this.contractAddress, innerNullifier!),
374
397
  this.anchorBlockHeader.hash(),
@@ -380,7 +403,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
380
403
  }
381
404
 
382
405
  /**
383
- * Fetches a message from the executionStore, given its key.
406
+ * Returns the membership witness of an un-nullified L1 to L2 message.
384
407
  * @param contractAddress - Address of a contract by which the message was emitted.
385
408
  * @param messageHash - Hash of the message.
386
409
  * @param secret - Secret used to compute a nullifier.
@@ -393,6 +416,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
393
416
  contractAddress,
394
417
  messageHash,
395
418
  secret,
419
+ await this.anchorBlockHeader.hash(),
396
420
  );
397
421
 
398
422
  return new MessageLoadOracleInputs(messageIndex, siblingPath);
@@ -405,29 +429,31 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
405
429
  * @param startStorageSlot - The starting storage slot.
406
430
  * @param numberOfElements - Number of elements to read from the starting storage slot.
407
431
  */
408
- public async storageRead(
432
+ public getFromPublicStorage(
409
433
  blockHash: BlockHash,
410
434
  contractAddress: AztecAddress,
411
435
  startStorageSlot: Fr,
412
436
  numberOfElements: number,
413
437
  ) {
414
- const slots = Array(numberOfElements)
415
- .fill(0)
416
- .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
438
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, async () => {
439
+ const slots = Array(numberOfElements)
440
+ .fill(0)
441
+ .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
417
442
 
418
- const values = await Promise.all(
419
- slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
420
- );
443
+ const values = await Promise.all(
444
+ slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
445
+ );
421
446
 
422
- this.logger.debug(
423
- `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
424
- );
447
+ this.logger.debug(
448
+ `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
449
+ );
425
450
 
426
- return values;
451
+ return values;
452
+ });
427
453
  }
428
454
 
429
455
  /**
430
- * Returns a per-contract logger whose output is prefixed with `contract_log::<name>(<addrAbbrev>)`.
456
+ * Returns a per-contract logger whose output is prefixed with `contract:<name>(<addrAbbrev>)`.
431
457
  */
432
458
  async #getContractLogger(): Promise<Logger> {
433
459
  if (!this.contractLogger) {
@@ -436,26 +462,47 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
436
462
  this.contractLogger = await createContractLogger(
437
463
  this.contractAddress,
438
464
  addr => this.contractStore.getDebugContractName(addr),
465
+ 'user',
439
466
  { instanceId: this.jobId },
440
467
  );
441
468
  }
442
469
  return this.contractLogger;
443
470
  }
444
471
 
472
+ /**
473
+ * Returns a per-contract logger whose output is prefixed with `aztecnr:<name>(<addrAbbrev>)`.
474
+ */
475
+ async #getAztecnrLogger(): Promise<Logger> {
476
+ if (!this.aztecnrLogger) {
477
+ // Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
478
+ // to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
479
+ this.aztecnrLogger = await createContractLogger(
480
+ this.contractAddress,
481
+ addr => this.contractStore.getDebugContractName(addr),
482
+ 'aztecnr',
483
+ { instanceId: this.jobId },
484
+ );
485
+ }
486
+ return this.aztecnrLogger;
487
+ }
488
+
445
489
  public async log(level: number, message: string, fields: Fr[]): Promise<void> {
446
490
  if (!LogLevels[level]) {
447
491
  throw new Error(`Invalid log level: ${level}`);
448
492
  }
449
- const logger = await this.#getContractLogger();
450
- logContractMessage(logger, LogLevels[level], message, fields);
493
+
494
+ const { kind, message: strippedMessage } = stripAztecnrLogPrefix(message);
495
+
496
+ const logger = kind == 'aztecnr' ? await this.#getAztecnrLogger() : await this.#getContractLogger();
497
+ logContractMessage(logger, LogLevels[level], strippedMessage, fields);
451
498
  }
452
499
 
453
- public async fetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
500
+ public async getPendingTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr, scope: AztecAddress) {
454
501
  const logService = new LogService(
455
502
  this.aztecNode,
456
503
  this.anchorBlockHeader,
457
504
  this.keyStore,
458
- this.capsuleStore,
505
+ this.capsuleService,
459
506
  this.recipientTaggingStore,
460
507
  this.senderAddressBookStore,
461
508
  this.addressStore,
@@ -463,7 +510,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
463
510
  this.logger.getBindings(),
464
511
  );
465
512
 
466
- await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
513
+ await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, scope);
467
514
  }
468
515
 
469
516
  /**
@@ -482,6 +529,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
482
529
  eventValidationRequestsArrayBaseSlot: Fr,
483
530
  maxNotePackedLen: number,
484
531
  maxEventSerializedLen: number,
532
+ scope: AztecAddress,
485
533
  ) {
486
534
  // TODO(#10727): allow other contracts to store notes
487
535
  if (!this.contractAddress.equals(contractAddress)) {
@@ -491,11 +539,21 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
491
539
  // We read all note and event validation requests and process them all concurrently. This makes the process much
492
540
  // faster as we don't need to wait for the network round-trip.
493
541
  const noteValidationRequests = (
494
- await this.capsuleStore.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, this.jobId)
542
+ await this.capsuleService.readCapsuleArray(
543
+ contractAddress,
544
+ noteValidationRequestsArrayBaseSlot,
545
+ this.jobId,
546
+ scope,
547
+ )
495
548
  ).map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
496
549
 
497
550
  const eventValidationRequests = (
498
- await this.capsuleStore.readCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, this.jobId)
551
+ await this.capsuleService.readCapsuleArray(
552
+ contractAddress,
553
+ eventValidationRequestsArrayBaseSlot,
554
+ this.jobId,
555
+ scope,
556
+ )
499
557
  ).map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
500
558
 
501
559
  const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
@@ -510,7 +568,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
510
568
  request.noteHash,
511
569
  request.nullifier,
512
570
  request.txHash,
513
- request.recipient,
571
+ scope,
514
572
  ),
515
573
  );
516
574
 
@@ -523,21 +581,34 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
523
581
  request.serializedEvent,
524
582
  request.eventCommitment,
525
583
  request.txHash,
526
- request.recipient,
584
+ scope,
527
585
  ),
528
586
  );
529
587
 
530
588
  await Promise.all([...noteStorePromises, ...eventStorePromises]);
531
589
 
532
590
  // Requests are cleared once we're done.
533
- await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, [], this.jobId);
534
- await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, [], this.jobId);
591
+ await this.capsuleService.setCapsuleArray(
592
+ contractAddress,
593
+ noteValidationRequestsArrayBaseSlot,
594
+ [],
595
+ this.jobId,
596
+ scope,
597
+ );
598
+ await this.capsuleService.setCapsuleArray(
599
+ contractAddress,
600
+ eventValidationRequestsArrayBaseSlot,
601
+ [],
602
+ this.jobId,
603
+ scope,
604
+ );
535
605
  }
536
606
 
537
- public async bulkRetrieveLogs(
607
+ public async getLogsByTag(
538
608
  contractAddress: AztecAddress,
539
609
  logRetrievalRequestsArrayBaseSlot: Fr,
540
610
  logRetrievalResponsesArrayBaseSlot: Fr,
611
+ scope: AztecAddress,
541
612
  ) {
542
613
  // TODO(#10727): allow other contracts to process partial notes
543
614
  if (!this.contractAddress.equals(contractAddress)) {
@@ -547,14 +618,14 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
547
618
  // We read all log retrieval requests and process them all concurrently. This makes the process much faster as we
548
619
  // don't need to wait for the network round-trip.
549
620
  const logRetrievalRequests = (
550
- await this.capsuleStore.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId)
621
+ await this.capsuleService.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId, scope)
551
622
  ).map(LogRetrievalRequest.fromFields);
552
623
 
553
624
  const logService = new LogService(
554
625
  this.aztecNode,
555
626
  this.anchorBlockHeader,
556
627
  this.keyStore,
557
- this.capsuleStore,
628
+ this.capsuleService,
558
629
  this.recipientTaggingStore,
559
630
  this.senderAddressBookStore,
560
631
  this.addressStore,
@@ -562,33 +633,47 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
562
633
  this.logger.getBindings(),
563
634
  );
564
635
 
565
- const maybeLogRetrievalResponses = await logService.bulkRetrieveLogs(logRetrievalRequests);
636
+ const maybeLogRetrievalResponses = await logService.fetchLogsByTag(contractAddress, logRetrievalRequests);
566
637
 
567
638
  // Requests are cleared once we're done.
568
- await this.capsuleStore.setCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, [], this.jobId);
639
+ await this.capsuleService.setCapsuleArray(
640
+ contractAddress,
641
+ logRetrievalRequestsArrayBaseSlot,
642
+ [],
643
+ this.jobId,
644
+ scope,
645
+ );
569
646
 
570
647
  // The responses are stored as Option<LogRetrievalResponse> in a second CapsuleArray.
571
- await this.capsuleStore.setCapsuleArray(
648
+ await this.capsuleService.setCapsuleArray(
572
649
  contractAddress,
573
650
  logRetrievalResponsesArrayBaseSlot,
574
651
  maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption),
575
652
  this.jobId,
653
+ scope,
576
654
  );
577
655
  }
578
656
 
579
- public async utilityResolveMessageContexts(
657
+ public async getMessageContextsByTxHash(
580
658
  contractAddress: AztecAddress,
581
659
  messageContextRequestsArrayBaseSlot: Fr,
582
660
  messageContextResponsesArrayBaseSlot: Fr,
661
+ scope: AztecAddress,
583
662
  ) {
584
663
  try {
585
664
  if (!this.contractAddress.equals(contractAddress)) {
586
665
  throw new Error(`Got a message context request from ${contractAddress}, expected ${this.contractAddress}`);
587
666
  }
588
- const requestCapsules = await this.capsuleStore.readCapsuleArray(
667
+
668
+ // TODO(@mverzilli): this is a prime example of where using a volatile array would make much more sense, we don't
669
+ // need scopes here, we just need a bit of shared memory to cross boundaries between Noir and TS.
670
+ // At the same time, we don't want to allow any global scope access other than where backwards compatibility
671
+ // forces us to. Hence we need the scope here to be artificial.
672
+ const requestCapsules = await this.capsuleService.readCapsuleArray(
589
673
  contractAddress,
590
674
  messageContextRequestsArrayBaseSlot,
591
675
  this.jobId,
676
+ scope,
592
677
  );
593
678
 
594
679
  const txHashes = requestCapsules.map((fields, i) => {
@@ -600,66 +685,73 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
600
685
  return fields[0];
601
686
  });
602
687
 
603
- const maybeMessageContexts = await this.messageContextService.resolveMessageContexts(
688
+ const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
604
689
  txHashes,
605
690
  this.anchorBlockHeader.getBlockNumber(),
606
691
  );
607
692
 
608
693
  // Leave response in response capsule array.
609
- await this.capsuleStore.setCapsuleArray(
694
+ await this.capsuleService.setCapsuleArray(
610
695
  contractAddress,
611
696
  messageContextResponsesArrayBaseSlot,
612
- maybeMessageContexts.map(MessageTxContext.toSerializedOption),
697
+ maybeMessageContexts.map(MessageContext.toSerializedOption),
613
698
  this.jobId,
699
+ scope,
614
700
  );
615
701
  } finally {
616
- await this.capsuleStore.setCapsuleArray(contractAddress, messageContextRequestsArrayBaseSlot, [], this.jobId);
702
+ await this.capsuleService.setCapsuleArray(
703
+ contractAddress,
704
+ messageContextRequestsArrayBaseSlot,
705
+ [],
706
+ this.jobId,
707
+ scope,
708
+ );
617
709
  }
618
710
  }
619
711
 
620
- public storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
712
+ public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
621
713
  if (!contractAddress.equals(this.contractAddress)) {
622
714
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
623
715
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
624
716
  }
625
- this.capsuleStore.storeCapsule(this.contractAddress, slot, capsule, this.jobId);
626
- return Promise.resolve();
717
+ this.capsuleService.setCapsule(contractAddress, slot, capsule, this.jobId, scope);
627
718
  }
628
719
 
629
- public async loadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
720
+ public getCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): Promise<Fr[] | null> {
630
721
  if (!contractAddress.equals(this.contractAddress)) {
631
722
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
632
723
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
633
724
  }
634
- return (
635
- // TODO(#12425): On the following line, the pertinent capsule gets overshadowed by the transient one. Tackle this.
636
- this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ??
637
- (await this.capsuleStore.loadCapsule(this.contractAddress, slot, this.jobId))
638
- );
725
+ return this.capsuleService.getCapsule(contractAddress, slot, this.jobId, scope, this.capsules);
639
726
  }
640
727
 
641
- public deleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
728
+ public deleteCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): void {
642
729
  if (!contractAddress.equals(this.contractAddress)) {
643
730
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
644
731
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
645
732
  }
646
- this.capsuleStore.deleteCapsule(this.contractAddress, slot, this.jobId);
647
- return Promise.resolve();
733
+ this.capsuleService.deleteCapsule(contractAddress, slot, this.jobId, scope);
648
734
  }
649
735
 
650
- public copyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
736
+ public copyCapsule(
737
+ contractAddress: AztecAddress,
738
+ srcSlot: Fr,
739
+ dstSlot: Fr,
740
+ numEntries: number,
741
+ scope: AztecAddress,
742
+ ): Promise<void> {
651
743
  if (!contractAddress.equals(this.contractAddress)) {
652
744
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
653
745
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
654
746
  }
655
- return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
747
+ return this.capsuleService.copyCapsule(contractAddress, srcSlot, dstSlot, numEntries, this.jobId, scope);
656
748
  }
657
749
 
658
750
  /**
659
751
  * Clears cached sync state for a contract for a set of scopes, forcing re-sync on the next query so that newly
660
752
  * stored notes or events are discovered.
661
753
  */
662
- public invalidateContractSyncCache(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
754
+ public setContractSyncCacheInvalid(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
663
755
  if (!contractAddress.equals(this.contractAddress)) {
664
756
  throw new Error(`Contract ${this.contractAddress} cannot invalidate sync cache of ${contractAddress}`);
665
757
  }
@@ -667,25 +759,30 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
667
759
  }
668
760
 
669
761
  // TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
670
- public aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
762
+ public decryptAes128(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
671
763
  const aes128 = new Aes128();
672
764
  return aes128.decryptBufferCBC(ciphertext, iv, symKey);
673
765
  }
674
766
 
675
767
  /**
676
- * Retrieves the shared secret for a given address and ephemeral public key.
768
+ * Retrieves the app-siloed shared secret for a given address and ephemeral public key.
677
769
  * @param address - The address to get the secret for.
678
770
  * @param ephPk - The ephemeral public key to get the secret for.
679
- * @returns The secret for the given address.
771
+ * @param contractAddress - The contract address for app-siloing (validated against execution context).
772
+ * @returns The app-siloed shared secret as a Field.
680
773
  */
681
- public async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
682
- // TODO(#12656): return an app-siloed secret
774
+ public async getSharedSecret(address: AztecAddress, ephPk: Point, contractAddress: AztecAddress): Promise<Fr> {
775
+ if (!contractAddress.equals(this.contractAddress)) {
776
+ throw new Error(
777
+ `getSharedSecret called with contract address ${contractAddress}, expected ${this.contractAddress}`,
778
+ );
779
+ }
683
780
  const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
684
781
  const ivskM = await this.keyStore.getMasterSecretKey(
685
782
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
686
783
  );
687
784
  const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
688
- return deriveEcdhSharedSecret(addressSecret, ephPk);
785
+ return deriveAppSiloedSharedSecret(addressSecret, ephPk, this.contractAddress);
689
786
  }
690
787
 
691
788
  public emitOffchainEffect(data: Fr[]): Promise<void> {
@@ -697,4 +794,24 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
697
794
  public getOffchainEffects(): OffchainEffect[] {
698
795
  return this.offchainEffects;
699
796
  }
797
+
798
+ /** Runs a query concurrently with a validation that the block hash is not ahead of the anchor block. */
799
+ async #queryWithBlockHashNotAfterAnchor<T>(blockHash: BlockHash, query: () => Promise<T>): Promise<T> {
800
+ const [response] = await Promise.all([
801
+ query(),
802
+ (async () => {
803
+ const header = await this.aztecNode.getBlockHeader(blockHash);
804
+ if (!header) {
805
+ throw new Error(`Could not find block header for block hash ${blockHash}`);
806
+ }
807
+
808
+ if (header.getBlockNumber() > this.anchorBlockHeader.getBlockNumber()) {
809
+ throw new Error(
810
+ `Made a node query with a reference block hash ${blockHash} with block number ${header.getBlockNumber()}, which is ahead of the anchor block number ${this.anchorBlockHeader.getBlockNumber()} (from anchor block hash ${await this.anchorBlockHeader.hash()}).`,
811
+ );
812
+ }
813
+ })(),
814
+ ]);
815
+ return response;
816
+ }
700
817
  }
@@ -5,18 +5,22 @@ import type { DebugLog } from '@aztec/stdlib/logs';
5
5
 
6
6
  /** Resolves a contract address to a human-readable name, if available. */
7
7
  export type ContractNameResolver = (address: AztecAddress) => Promise<string | undefined>;
8
+ export type CONTRACT_LOG_KIND = 'aztecnr' | 'user';
8
9
 
9
10
  /**
10
- * Creates a logger whose output is prefixed with `contract_log::<name>(<addrAbbrev>)`.
11
+ * Creates a logger whose output is prefixed with `contract:<name>(<addrAbbrev>)`.
11
12
  */
12
13
  export async function createContractLogger(
13
14
  contractAddress: AztecAddress,
14
15
  getContractName: ContractNameResolver,
16
+ kind: CONTRACT_LOG_KIND,
15
17
  options?: { instanceId?: string },
16
18
  ): Promise<Logger> {
17
19
  const addrAbbrev = contractAddress.toString().slice(0, 10);
18
20
  const name = await getContractName(contractAddress);
19
- const module = name ? `contract_log::${name}(${addrAbbrev})` : `contract_log::Unknown(${addrAbbrev})`;
21
+
22
+ const prefix = kind == 'aztecnr' ? 'aztecnr' : 'contract';
23
+ const module = name ? `${prefix}:${name}(${addrAbbrev})` : `${prefix}:Unknown(${addrAbbrev})`;
20
24
  return createLogger(module, options);
21
25
  }
22
26
 
@@ -29,11 +33,20 @@ export function logContractMessage(logger: Logger, level: LogLevel, message: str
29
33
 
30
34
  /**
31
35
  * Displays debug logs collected during public function simulation,
32
- * using the `contract_log::` prefixed logger format.
36
+ * using the `contract:` prefixed logger format.
33
37
  */
34
38
  export async function displayDebugLogs(debugLogs: DebugLog[], getContractName: ContractNameResolver): Promise<void> {
35
39
  for (const log of debugLogs) {
36
- const logger = await createContractLogger(log.contractAddress, getContractName);
37
- logContractMessage(logger, log.level, log.message, log.fields);
40
+ const { kind, message } = stripAztecnrLogPrefix(log.message);
41
+ const logger = await createContractLogger(log.contractAddress, getContractName, kind);
42
+ logContractMessage(logger, log.level, message, log.fields);
43
+ }
44
+ }
45
+
46
+ export function stripAztecnrLogPrefix(message: string): { kind: CONTRACT_LOG_KIND; message: string } {
47
+ if (message.startsWith('[aztec-nr] ')) {
48
+ return { kind: 'aztecnr', message: message.slice('[aztec-nr] '.length) };
49
+ } else {
50
+ return { kind: 'user', message };
38
51
  }
39
52
  }