@aztec/pxe 0.0.1-commit.e588bc7e5 → 0.0.1-commit.e5a3663dd

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 (134) hide show
  1. package/dest/bin/check_oracle_version.js +4 -4
  2. package/dest/block_synchronizer/block_stream_source.d.ts +10 -0
  3. package/dest/block_synchronizer/block_stream_source.d.ts.map +1 -0
  4. package/dest/block_synchronizer/block_stream_source.js +37 -0
  5. package/dest/block_synchronizer/block_synchronizer.d.ts +6 -2
  6. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  7. package/dest/block_synchronizer/block_synchronizer.js +24 -10
  8. package/dest/config/index.d.ts +1 -1
  9. package/dest/config/index.d.ts.map +1 -1
  10. package/dest/config/index.js +7 -14
  11. package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -1
  12. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  13. package/dest/contract_function_simulator/contract_function_simulator.js +8 -5
  14. package/dest/contract_function_simulator/ephemeral_array_service.d.ts +28 -0
  15. package/dest/contract_function_simulator/ephemeral_array_service.d.ts.map +1 -0
  16. package/dest/contract_function_simulator/ephemeral_array_service.js +78 -0
  17. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +1 -1
  18. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
  19. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts +1 -1
  20. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.js +1 -1
  21. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +1 -1
  22. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -1
  23. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +1 -1
  24. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
  25. package/dest/contract_function_simulator/oracle/interfaces.d.ts +15 -2
  26. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  27. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +1 -1
  28. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -1
  29. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +10 -1
  30. package/dest/contract_function_simulator/oracle/oracle.d.ts +14 -2
  31. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  32. package/dest/contract_function_simulator/oracle/oracle.js +105 -3
  33. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +10 -11
  34. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  35. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +21 -17
  36. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +34 -13
  37. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  38. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +149 -28
  39. package/dest/contract_function_simulator/pick_notes.d.ts +1 -1
  40. package/dest/contract_function_simulator/pick_notes.d.ts.map +1 -1
  41. package/dest/contract_function_simulator/pick_notes.js +20 -3
  42. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts +1 -1
  43. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts.map +1 -1
  44. package/dest/contract_function_simulator/proxied_contract_data_source.js +3 -0
  45. package/dest/contract_sync/contract_sync_service.d.ts +1 -1
  46. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  47. package/dest/contract_sync/contract_sync_service.js +35 -23
  48. package/dest/entrypoints/client/bundle/utils.d.ts +2 -2
  49. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  50. package/dest/entrypoints/client/bundle/utils.js +2 -2
  51. package/dest/entrypoints/client/lazy/utils.d.ts +2 -2
  52. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  53. package/dest/entrypoints/client/lazy/utils.js +2 -2
  54. package/dest/entrypoints/pxe_creation_options.d.ts +3 -1
  55. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  56. package/dest/entrypoints/pxe_creation_options.js +3 -1
  57. package/dest/entrypoints/server/index.d.ts +2 -2
  58. package/dest/entrypoints/server/index.d.ts.map +1 -1
  59. package/dest/entrypoints/server/index.js +1 -1
  60. package/dest/entrypoints/server/utils.d.ts +2 -2
  61. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  62. package/dest/entrypoints/server/utils.js +2 -2
  63. package/dest/events/event_service.d.ts +1 -1
  64. package/dest/events/event_service.d.ts.map +1 -1
  65. package/dest/events/event_service.js +10 -1
  66. package/dest/events/private_event_filter_validator.d.ts +3 -2
  67. package/dest/events/private_event_filter_validator.d.ts.map +1 -1
  68. package/dest/events/private_event_filter_validator.js +15 -0
  69. package/dest/logs/log_service.d.ts +6 -6
  70. package/dest/logs/log_service.d.ts.map +1 -1
  71. package/dest/logs/log_service.js +8 -20
  72. package/dest/oracle_version.d.ts +4 -3
  73. package/dest/oracle_version.d.ts.map +1 -1
  74. package/dest/oracle_version.js +20 -10
  75. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  76. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  77. package/dest/private_kernel/private_kernel_execution_prover.js +4 -7
  78. package/dest/private_kernel/private_kernel_oracle.d.ts +5 -5
  79. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  80. package/dest/private_kernel/private_kernel_oracle.js +12 -15
  81. package/dest/pxe.d.ts +16 -4
  82. package/dest/pxe.d.ts.map +1 -1
  83. package/dest/pxe.js +49 -20
  84. package/dest/storage/anchor_block_store/anchor_block_store.js +1 -1
  85. package/dest/storage/capsule_store/capsule_store.d.ts +1 -1
  86. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  87. package/dest/storage/capsule_store/capsule_store.js +8 -5
  88. package/dest/storage/contract_store/contract_store.d.ts +1 -1
  89. package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
  90. package/dest/storage/contract_store/contract_store.js +4 -2
  91. package/dest/storage/private_event_store/private_event_store.d.ts +1 -1
  92. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  93. package/dest/storage/private_event_store/private_event_store.js +3 -0
  94. package/dest/storage/private_event_store/stored_private_event.js +1 -1
  95. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +2 -2
  96. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  97. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +2 -16
  98. package/package.json +16 -16
  99. package/src/bin/check_oracle_version.ts +4 -4
  100. package/src/block_synchronizer/block_stream_source.ts +52 -0
  101. package/src/block_synchronizer/block_synchronizer.ts +27 -11
  102. package/src/config/index.ts +2 -8
  103. package/src/contract_function_simulator/contract_function_simulator.ts +8 -4
  104. package/src/contract_function_simulator/ephemeral_array_service.ts +110 -0
  105. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
  106. package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +1 -1
  107. package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +1 -1
  108. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
  109. package/src/contract_function_simulator/oracle/interfaces.ts +30 -1
  110. package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +7 -1
  111. package/src/contract_function_simulator/oracle/oracle.ts +157 -3
  112. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +34 -20
  113. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +241 -55
  114. package/src/contract_function_simulator/pick_notes.ts +22 -3
  115. package/src/contract_function_simulator/proxied_contract_data_source.ts +8 -1
  116. package/src/contract_sync/contract_sync_service.ts +57 -51
  117. package/src/entrypoints/client/bundle/utils.ts +2 -3
  118. package/src/entrypoints/client/lazy/utils.ts +2 -3
  119. package/src/entrypoints/pxe_creation_options.ts +7 -0
  120. package/src/entrypoints/server/index.ts +1 -1
  121. package/src/entrypoints/server/utils.ts +2 -3
  122. package/src/events/event_service.ts +13 -1
  123. package/src/events/private_event_filter_validator.ts +21 -1
  124. package/src/logs/log_service.ts +14 -50
  125. package/src/oracle_version.ts +20 -10
  126. package/src/private_kernel/private_kernel_execution_prover.ts +4 -9
  127. package/src/private_kernel/private_kernel_oracle.ts +14 -14
  128. package/src/pxe.ts +86 -24
  129. package/src/storage/anchor_block_store/anchor_block_store.ts +1 -1
  130. package/src/storage/capsule_store/capsule_store.ts +15 -5
  131. package/src/storage/contract_store/contract_store.ts +8 -6
  132. package/src/storage/private_event_store/private_event_store.ts +4 -0
  133. package/src/storage/private_event_store/stored_private_event.ts +1 -1
  134. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +5 -15
@@ -7,9 +7,18 @@ import { LogLevels, type Logger, createLogger } from '@aztec/foundation/log';
7
7
  import type { MembershipWitness } from '@aztec/foundation/trees';
8
8
  import type { KeyStore } from '@aztec/key-store';
9
9
  import { isProtocolContract } from '@aztec/protocol-contracts';
10
+ import {
11
+ type CircuitSimulator,
12
+ ExecutionError,
13
+ extractCallStack,
14
+ resolveAssertionMessageFromError,
15
+ toACVMWitness,
16
+ witnessMapToFields,
17
+ } from '@aztec/simulator/client';
18
+ import { FunctionSelector } from '@aztec/stdlib/abi';
10
19
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
11
20
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
12
- import { BlockHash } from '@aztec/stdlib/block';
21
+ import { BlockHash, type L2TipsProvider } from '@aztec/stdlib/block';
13
22
  import type { CompleteAddress, ContractInstance, PartialAddress } from '@aztec/stdlib/contract';
14
23
  import { siloNullifier } from '@aztec/stdlib/hash';
15
24
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
@@ -27,7 +36,7 @@ import { EventService } from '../../events/event_service.js';
27
36
  import { LogService } from '../../logs/log_service.js';
28
37
  import { MessageContextService } from '../../messages/message_context_service.js';
29
38
  import { NoteService } from '../../notes/note_service.js';
30
- import { ORACLE_VERSION } from '../../oracle_version.js';
39
+ import { ORACLE_VERSION_MAJOR } from '../../oracle_version.js';
31
40
  import type { AddressStore } from '../../storage/address_store/address_store.js';
32
41
  import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
33
42
  import type { ContractStore } from '../../storage/contract_store/contract_store.js';
@@ -35,6 +44,7 @@ import type { NoteStore } from '../../storage/note_store/note_store.js';
35
44
  import type { PrivateEventStore } from '../../storage/private_event_store/private_event_store.js';
36
45
  import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
37
46
  import type { SenderAddressBookStore } from '../../storage/tagging_store/sender_address_book_store.js';
47
+ import { EphemeralArrayService } from '../ephemeral_array_service.js';
38
48
  import { EventValidationRequest } from '../noir-structs/event_validation_request.js';
39
49
  import { LogRetrievalRequest } from '../noir-structs/log_retrieval_request.js';
40
50
  import { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
@@ -43,6 +53,7 @@ import { UtilityContext } from '../noir-structs/utility_context.js';
43
53
  import { pickNotes } from '../pick_notes.js';
44
54
  import type { IMiscOracle, IUtilityExecutionOracle, NoteData } from './interfaces.js';
45
55
  import { MessageLoadOracleInputs } from './message_load_oracle_inputs.js';
56
+ import { Oracle } from './oracle.js';
46
57
 
47
58
  /** Args for UtilityExecutionOracle constructor. */
48
59
  export type UtilityExecutionOracleArgs = {
@@ -62,9 +73,11 @@ export type UtilityExecutionOracleArgs = {
62
73
  privateEventStore: PrivateEventStore;
63
74
  messageContextService: MessageContextService;
64
75
  contractSyncService: ContractSyncService;
76
+ l2TipsStore: L2TipsProvider;
65
77
  jobId: string;
66
78
  log?: ReturnType<typeof createLogger>;
67
79
  scopes: AztecAddress[];
80
+ simulator: CircuitSimulator;
68
81
  };
69
82
 
70
83
  /**
@@ -77,6 +90,10 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
77
90
  private contractLogger: Logger | undefined;
78
91
  private aztecnrLogger: Logger | undefined;
79
92
  private offchainEffects: OffchainEffect[] = [];
93
+ private readonly ephemeralArrayService = new EphemeralArrayService();
94
+
95
+ // We store oracle version to be able to show a nice error message when an oracle handler is missing.
96
+ private contractOracleVersion: { major: number; minor: number } | undefined;
80
97
 
81
98
  protected readonly contractAddress: AztecAddress;
82
99
  protected readonly authWitnesses: AuthWitness[];
@@ -93,9 +110,11 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
93
110
  protected readonly privateEventStore: PrivateEventStore;
94
111
  protected readonly messageContextService: MessageContextService;
95
112
  protected readonly contractSyncService: ContractSyncService;
113
+ protected readonly l2TipsStore: L2TipsProvider;
96
114
  protected readonly jobId: string;
97
115
  protected logger: ReturnType<typeof createLogger>;
98
116
  protected readonly scopes: AztecAddress[];
117
+ protected readonly simulator: CircuitSimulator;
99
118
 
100
119
  constructor(args: UtilityExecutionOracleArgs) {
101
120
  this.contractAddress = args.contractAddress;
@@ -113,12 +132,14 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
113
132
  this.privateEventStore = args.privateEventStore;
114
133
  this.messageContextService = args.messageContextService;
115
134
  this.contractSyncService = args.contractSyncService;
135
+ this.l2TipsStore = args.l2TipsStore;
116
136
  this.jobId = args.jobId;
117
137
  this.logger = args.log ?? createLogger('simulator:client_view_context');
118
138
  this.scopes = args.scopes;
139
+ this.simulator = args.simulator;
119
140
  }
120
141
 
121
- public assertCompatibleOracleVersion(version: number): void {
142
+ public assertCompatibleOracleVersion(major: number, minor: number): void {
122
143
  // TODO(F-416): Remove this hack on v5 when protocol contracts are redeployed.
123
144
  // Protocol contracts/canonical contracts shipped with committed bytecode that cannot be changed. Assert they use
124
145
  // the expected pinned version or the current one. We want to allow for both the pinned and the current versions
@@ -126,27 +147,36 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
126
147
  // pinned contracts (like e.g. next)
127
148
  const LEGACY_ORACLE_VERSION = 12;
128
149
  if (isProtocolContract(this.contractAddress)) {
129
- if (version !== LEGACY_ORACLE_VERSION && version !== ORACLE_VERSION) {
150
+ if (major !== LEGACY_ORACLE_VERSION && major !== ORACLE_VERSION_MAJOR) {
130
151
  const hint =
131
- version > ORACLE_VERSION
152
+ major > ORACLE_VERSION_MAJOR
132
153
  ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
133
154
  : '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.';
134
155
  throw new Error(
135
- `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle version ${LEGACY_ORACLE_VERSION} or ${ORACLE_VERSION}, got ${version})`,
156
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${LEGACY_ORACLE_VERSION} or ${ORACLE_VERSION_MAJOR}, got ${major})`,
136
157
  );
137
158
  }
159
+ this.contractOracleVersion = { major, minor };
138
160
  return;
139
161
  }
140
162
 
141
- if (version !== ORACLE_VERSION) {
163
+ if (major !== ORACLE_VERSION_MAJOR) {
142
164
  const hint =
143
- version > ORACLE_VERSION
165
+ major > ORACLE_VERSION_MAJOR
144
166
  ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
145
167
  : '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.';
146
168
  throw new Error(
147
- `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle version ${ORACLE_VERSION}, got ${version})`,
169
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
148
170
  );
149
171
  }
172
+
173
+ // Major matches - store both major and minor for later diagnostics (e.g. when an oracle is not found)
174
+ this.contractOracleVersion = { major, minor };
175
+ }
176
+
177
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
178
+ public nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
179
+ return this.contractOracleVersion;
150
180
  }
151
181
 
152
182
  public getRandomField(): Fr {
@@ -316,10 +346,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
316
346
  }
317
347
 
318
348
  /**
319
- * Returns an auth witness for the given message hash. Checks on the list of transient witnesses
320
- * for this transaction first, and falls back to the local database if not found.
349
+ * Returns an auth witness for the given message hash from the list of transient witnesses for this transaction.
321
350
  * @param messageHash - Hash of the message to authenticate.
322
- * @returns Authentication witness for the requested message hash.
351
+ * @returns Authentication witness for the requested message hash, or undefined if not found.
323
352
  */
324
353
  public getAuthWitness(messageHash: Fr): Promise<Fr[] | undefined> {
325
354
  return Promise.resolve(this.authWitnesses.find(w => w.requestHash.equals(messageHash))?.witness);
@@ -493,31 +522,44 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
493
522
  logContractMessage(logger, LogLevels[level], strippedMessage, fields);
494
523
  }
495
524
 
525
+ // Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
496
526
  public async getPendingTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr, scope: AztecAddress) {
497
- const logService = new LogService(
527
+ const logService = this.#createLogService();
528
+ const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
529
+ await this.capsuleService.appendToCapsuleArray(
530
+ this.contractAddress,
531
+ pendingTaggedLogArrayBaseSlot,
532
+ logs.map(log => log.toFields()),
533
+ this.jobId,
534
+ scope,
535
+ );
536
+ }
537
+
538
+ /** Fetches pending tagged logs into a freshly allocated ephemeral array and returns its base slot. */
539
+ public async getPendingTaggedLogsV2(scope: AztecAddress): Promise<Fr> {
540
+ const logService = this.#createLogService();
541
+ const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
542
+ return this.ephemeralArrayService.newArray(logs.map(log => log.toFields()));
543
+ }
544
+
545
+ #createLogService(): LogService {
546
+ return new LogService(
498
547
  this.aztecNode,
499
548
  this.anchorBlockHeader,
549
+ this.l2TipsStore,
500
550
  this.keyStore,
501
- this.capsuleService,
502
551
  this.recipientTaggingStore,
503
552
  this.senderAddressBookStore,
504
553
  this.addressStore,
505
554
  this.jobId,
506
555
  this.logger.getBindings(),
507
556
  );
508
-
509
- await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, scope);
510
557
  }
511
558
 
512
559
  /**
513
- * Validates all note and event validation requests enqueued via `enqueue_note_for_validation` and
514
- * `enqueue_event_for_validation`, inserting them into the note database and event store respectively, making them
515
- * queryable via `get_notes` and `getPrivateEvents`.
560
+ * Legacy: validates note/event requests stored in capsule arrays.
516
561
  *
517
- * This automatically clears both validation request queues, so no further work needs to be done by the caller.
518
- * @param contractAddress - The address of the contract that the logs are tagged for.
519
- * @param noteValidationRequestsArrayBaseSlot - The base slot of capsule array containing note validation requests.
520
- * @param eventValidationRequestsArrayBaseSlot - The base slot of capsule array containing event validation requests.
562
+ * Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
521
563
  */
522
564
  public async validateAndStoreEnqueuedNotesAndEvents(
523
565
  contractAddress: AztecAddress,
@@ -532,8 +574,6 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
532
574
  throw new Error(`Got a note validation request from ${contractAddress}, expected ${this.contractAddress}`);
533
575
  }
534
576
 
535
- // We read all note and event validation requests and process them all concurrently. This makes the process much
536
- // faster as we don't need to wait for the network round-trip.
537
577
  const noteValidationRequests = (
538
578
  await this.capsuleService.readCapsuleArray(
539
579
  contractAddress,
@@ -552,6 +592,53 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
552
592
  )
553
593
  ).map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
554
594
 
595
+ await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
596
+
597
+ await this.capsuleService.setCapsuleArray(
598
+ contractAddress,
599
+ noteValidationRequestsArrayBaseSlot,
600
+ [],
601
+ this.jobId,
602
+ scope,
603
+ );
604
+ await this.capsuleService.setCapsuleArray(
605
+ contractAddress,
606
+ eventValidationRequestsArrayBaseSlot,
607
+ [],
608
+ this.jobId,
609
+ scope,
610
+ );
611
+ }
612
+
613
+ public async validateAndStoreEnqueuedNotesAndEventsV2(
614
+ noteValidationRequestsArrayBaseSlot: Fr,
615
+ eventValidationRequestsArrayBaseSlot: Fr,
616
+ maxNotePackedLen: number,
617
+ maxEventSerializedLen: number,
618
+ scope: AztecAddress,
619
+ ) {
620
+ const noteValidationRequests = this.ephemeralArrayService
621
+ .readArrayAt(noteValidationRequestsArrayBaseSlot)
622
+ .map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
623
+
624
+ const eventValidationRequests = this.ephemeralArrayService
625
+ .readArrayAt(eventValidationRequestsArrayBaseSlot)
626
+ .map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
627
+
628
+ await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
629
+ }
630
+
631
+ /**
632
+ * Dispatches note and event validation requests to the service layer.
633
+ *
634
+ * This function is an auxiliary to support legacy (capsule backed) and new (ephemeral array backed) versions of the
635
+ * `validateAndStoreEnqueuedNotesAndEvents` oracle.
636
+ */
637
+ async #processValidationRequests(
638
+ noteValidationRequests: NoteValidationRequest[],
639
+ eventValidationRequests: EventValidationRequest[],
640
+ scope: AztecAddress,
641
+ ) {
555
642
  const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
556
643
  const noteStorePromises = noteValidationRequests.map(request =>
557
644
  noteService.validateAndStoreNote(
@@ -582,22 +669,6 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
582
669
  );
583
670
 
584
671
  await Promise.all([...noteStorePromises, ...eventStorePromises]);
585
-
586
- // Requests are cleared once we're done.
587
- await this.capsuleService.setCapsuleArray(
588
- contractAddress,
589
- noteValidationRequestsArrayBaseSlot,
590
- [],
591
- this.jobId,
592
- scope,
593
- );
594
- await this.capsuleService.setCapsuleArray(
595
- contractAddress,
596
- eventValidationRequestsArrayBaseSlot,
597
- [],
598
- this.jobId,
599
- scope,
600
- );
601
672
  }
602
673
 
603
674
  public async getLogsByTag(
@@ -617,18 +688,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
617
688
  await this.capsuleService.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId, scope)
618
689
  ).map(LogRetrievalRequest.fromFields);
619
690
 
620
- const logService = new LogService(
621
- this.aztecNode,
622
- this.anchorBlockHeader,
623
- this.keyStore,
624
- this.capsuleService,
625
- this.recipientTaggingStore,
626
- this.senderAddressBookStore,
627
- this.addressStore,
628
- this.jobId,
629
- this.logger.getBindings(),
630
- );
631
-
691
+ const logService = this.#createLogService();
632
692
  const maybeLogRetrievalResponses = await logService.fetchLogsByTag(contractAddress, logRetrievalRequests);
633
693
 
634
694
  // Requests are cleared once we're done.
@@ -650,6 +710,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
650
710
  );
651
711
  }
652
712
 
713
+ public async getLogsByTagV2(requestArrayBaseSlot: Fr): Promise<Fr> {
714
+ const logRetrievalRequests = this.ephemeralArrayService
715
+ .readArrayAt(requestArrayBaseSlot)
716
+ .map(LogRetrievalRequest.fromFields);
717
+ const logService = this.#createLogService();
718
+
719
+ const maybeLogRetrievalResponses = await logService.fetchLogsByTag(this.contractAddress, logRetrievalRequests);
720
+
721
+ return this.ephemeralArrayService.newArray(maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption));
722
+ }
723
+
724
+ // Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
653
725
  public async getMessageContextsByTxHash(
654
726
  contractAddress: AztecAddress,
655
727
  messageContextRequestsArrayBaseSlot: Fr,
@@ -661,7 +733,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
661
733
  throw new Error(`Got a message context request from ${contractAddress}, expected ${this.contractAddress}`);
662
734
  }
663
735
 
664
- // TODO(@mverzilli): this is a prime example of where using a volatile array would make much more sense, we don't
736
+ // TODO(@mverzilli): this is a prime example of where using an ephemeral array would make much more sense, we don't
665
737
  // need scopes here, we just need a bit of shared memory to cross boundaries between Noir and TS.
666
738
  // At the same time, we don't want to allow any global scope access other than where backwards compatibility
667
739
  // forces us to. Hence we need the scope here to be artificial.
@@ -705,6 +777,27 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
705
777
  }
706
778
  }
707
779
 
780
+ /** Reads tx hash requests from an ephemeral array, resolves their contexts, and returns the response slot. */
781
+ public async getMessageContextsByTxHashV2(requestArrayBaseSlot: Fr): Promise<Fr> {
782
+ const requestFields = this.ephemeralArrayService.readArrayAt(requestArrayBaseSlot);
783
+
784
+ const txHashes = requestFields.map((fields, i) => {
785
+ if (fields.length !== 1) {
786
+ throw new Error(
787
+ `Malformed message context request at index ${i}: expected 1 field (tx hash), got ${fields.length}`,
788
+ );
789
+ }
790
+ return fields[0];
791
+ });
792
+
793
+ const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
794
+ txHashes,
795
+ this.anchorBlockHeader.getBlockNumber(),
796
+ );
797
+
798
+ return this.ephemeralArrayService.newArray(maybeMessageContexts.map(MessageContext.toSerializedOption));
799
+ }
800
+
708
801
  public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
709
802
  if (!contractAddress.equals(this.contractAddress)) {
710
803
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
@@ -781,11 +874,103 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
781
874
  return deriveAppSiloedSharedSecret(addressSecret, ephPk, this.contractAddress);
782
875
  }
783
876
 
877
+ public pushEphemeral(slot: Fr, elements: Fr[]): number {
878
+ return this.ephemeralArrayService.push(slot, elements);
879
+ }
880
+
881
+ public popEphemeral(slot: Fr): Fr[] {
882
+ return this.ephemeralArrayService.pop(slot);
883
+ }
884
+
885
+ public getEphemeral(slot: Fr, index: number): Fr[] {
886
+ return this.ephemeralArrayService.get(slot, index);
887
+ }
888
+
889
+ public setEphemeral(slot: Fr, index: number, elements: Fr[]): void {
890
+ this.ephemeralArrayService.set(slot, index, elements);
891
+ }
892
+
893
+ public getEphemeralLen(slot: Fr): number {
894
+ return this.ephemeralArrayService.len(slot);
895
+ }
896
+
897
+ public removeEphemeral(slot: Fr, index: number): void {
898
+ this.ephemeralArrayService.remove(slot, index);
899
+ }
900
+
901
+ public clearEphemeral(slot: Fr): void {
902
+ this.ephemeralArrayService.clear(slot);
903
+ }
904
+
784
905
  public emitOffchainEffect(data: Fr[]): Promise<void> {
785
906
  this.offchainEffects.push({ data, contractAddress: this.contractAddress });
786
907
  return Promise.resolve();
787
908
  }
788
909
 
910
+ /** Executes another utility function from within this one and returns its serialized return values. */
911
+ public async callUtilityFunction(
912
+ targetContractAddress: AztecAddress,
913
+ functionSelector: FunctionSelector,
914
+ args: Fr[],
915
+ ): Promise<Fr[]> {
916
+ // TODO(F-29): We want to support cross-contract utility calls, but doing so safely requires wallets to have
917
+ // a way to authorize which contracts can be called transitively, since those calls may expose private state.
918
+ // Until that is in place, restrict nested utility calls to the same contract only.
919
+ if (!targetContractAddress.equals(this.contractAddress)) {
920
+ throw new Error(
921
+ `Cross-contract utility calls are not yet supported: cannot call ${targetContractAddress} from utility function on ${this.contractAddress}.`,
922
+ );
923
+ }
924
+
925
+ this.logger.debug(
926
+ `Calling nested utility function ${targetContractAddress}:${functionSelector} from ${this.contractAddress}`,
927
+ );
928
+
929
+ const targetArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(
930
+ targetContractAddress,
931
+ functionSelector,
932
+ );
933
+
934
+ const nestedOracle = new UtilityExecutionOracle({
935
+ contractAddress: targetContractAddress,
936
+ authWitnesses: this.authWitnesses,
937
+ capsules: this.capsules,
938
+ anchorBlockHeader: this.anchorBlockHeader,
939
+ contractStore: this.contractStore,
940
+ noteStore: this.noteStore,
941
+ keyStore: this.keyStore,
942
+ addressStore: this.addressStore,
943
+ aztecNode: this.aztecNode,
944
+ recipientTaggingStore: this.recipientTaggingStore,
945
+ senderAddressBookStore: this.senderAddressBookStore,
946
+ capsuleService: this.capsuleService,
947
+ privateEventStore: this.privateEventStore,
948
+ messageContextService: this.messageContextService,
949
+ contractSyncService: this.contractSyncService,
950
+ l2TipsStore: this.l2TipsStore,
951
+ jobId: this.jobId,
952
+ scopes: this.scopes,
953
+ simulator: this.simulator,
954
+ log: this.logger,
955
+ });
956
+
957
+ const initialWitness = toACVMWitness(0, args);
958
+ const acvmCallback = new Oracle(nestedOracle);
959
+ const acirExecutionResult = await this.simulator
960
+ .executeUserCircuit(initialWitness, targetArtifact, acvmCallback.toACIRCallback())
961
+ .catch((err: Error) => {
962
+ err.message = resolveAssertionMessageFromError(err, targetArtifact);
963
+ throw new ExecutionError(
964
+ err.message,
965
+ { contractAddress: targetContractAddress, functionSelector },
966
+ extractCallStack(err, targetArtifact.debug),
967
+ { cause: err },
968
+ );
969
+ });
970
+
971
+ return witnessMapToFields(acirExecutionResult.returnWitness);
972
+ }
973
+
789
974
  /** Returns offchain effects collected during execution. */
790
975
  public getOffchainEffects(): OffchainEffect[] {
791
976
  return this.offchainEffects;
@@ -796,7 +981,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
796
981
  const [response] = await Promise.all([
797
982
  query(),
798
983
  (async () => {
799
- const header = await this.aztecNode.getBlockHeader(blockHash);
984
+ const block = await this.aztecNode.getBlock(blockHash);
985
+ const header = block?.header;
800
986
  if (!header) {
801
987
  throw new Error(`Could not find block header for block hash ${blockHash}`);
802
988
  }
@@ -85,9 +85,24 @@ interface ContainsNote {
85
85
  }
86
86
 
87
87
  const selectPropertyFromPackedNoteContent = (noteData: Fr[], selector: PropertySelector): Fr => {
88
+ if (selector.index >= noteData.length) {
89
+ throw new Error(`Property selector index ${selector.index} out of bounds for note with ${noteData.length} fields`);
90
+ }
91
+ if (selector.offset + selector.length > Fr.SIZE_IN_BYTES) {
92
+ throw new Error(
93
+ `Property selector range (offset=${selector.offset}, length=${selector.length}) exceeds Fr buffer size of ${Fr.SIZE_IN_BYTES} bytes`,
94
+ );
95
+ }
88
96
  const noteValueBuffer = noteData[selector.index].toBuffer();
89
- const noteValue = noteValueBuffer.subarray(selector.offset, selector.offset + selector.length);
90
- return Fr.fromBuffer(noteValue);
97
+ // Noir's PropertySelector counts offset from the LSB (last byte of the big-endian buffer),
98
+ // so offset=0,length=Fr.SIZE_IN_BYTES reads the entire field, and offset=0,length=1 reads the last byte.
99
+ const start = Fr.SIZE_IN_BYTES - selector.offset - selector.length;
100
+ const end = Fr.SIZE_IN_BYTES - selector.offset;
101
+ const noteValue = noteValueBuffer.subarray(start, end);
102
+ // Left-pad to Fr.SIZE_IN_BYTES so Fr.fromBuffer interprets the value correctly.
103
+ const padded = Buffer.alloc(Fr.SIZE_IN_BYTES);
104
+ noteValue.copy(padded, Fr.SIZE_IN_BYTES - noteValue.length);
105
+ return Fr.fromBuffer(padded);
91
106
  };
92
107
 
93
108
  const selectNotes = <T extends ContainsNote>(noteDatas: T[], selects: Select[]): T[] =>
@@ -103,7 +118,11 @@ const selectNotes = <T extends ContainsNote>(noteDatas: T[], selects: Select[]):
103
118
  [Comparator.GTE]: () => !noteValueFr.lt(value),
104
119
  };
105
120
 
106
- return comparatorSelector[comparator]();
121
+ const fn = comparatorSelector[comparator];
122
+ if (!fn) {
123
+ throw new Error(`Invalid comparator value: ${comparator}`);
124
+ }
125
+ return fn();
107
126
  }),
108
127
  );
109
128
 
@@ -29,6 +29,7 @@ export class ProxiedContractStoreFactory {
29
29
  }
30
30
  instance.currentContractClassId = realInstance.currentContractClassId;
31
31
  instance.originalContractClassId = realInstance.originalContractClassId;
32
+ instance.initializationHash = realInstance.initializationHash;
32
33
  return instance;
33
34
  } else {
34
35
  return target.getContractInstance(address);
@@ -47,6 +48,9 @@ export class ProxiedContractStoreFactory {
47
48
  return fn;
48
49
  }
49
50
  }
51
+ throw new Error(
52
+ `Function with selector ${selector} not found in stub artifact for overridden contract at ${contractAddress}. The stub does not implement this function.`,
53
+ );
50
54
  } else {
51
55
  return target.getFunctionArtifact(contractAddress, selector);
52
56
  }
@@ -64,6 +68,9 @@ export class ProxiedContractStoreFactory {
64
68
  return fn;
65
69
  }
66
70
  }
71
+ throw new Error(
72
+ `Function with selector ${selector} not found in stub artifact for overridden contract at ${contractAddress}. The stub does not implement this function.`,
73
+ );
67
74
  } else {
68
75
  return target.getFunctionArtifactWithDebugMetadata(contractAddress, selector);
69
76
  }
@@ -78,6 +85,6 @@ export class ProxiedContractStoreFactory {
78
85
  }
79
86
  }
80
87
  },
81
- });
88
+ }) satisfies ContractStore;
82
89
  }
83
90
  }