@aztec/pxe 0.0.1-commit.3e3d0c9cd → 0.0.1-commit.3f5453c7b

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 (155) hide show
  1. package/dest/bin/check_oracle_version.js +4 -4
  2. package/dest/block_synchronizer/block_synchronizer.d.ts +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  4. package/dest/block_synchronizer/block_synchronizer.js +6 -0
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts +3 -4
  6. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  7. package/dest/contract_function_simulator/contract_function_simulator.js +13 -4
  8. package/dest/contract_function_simulator/ephemeral_array_service.d.ts +28 -0
  9. package/dest/contract_function_simulator/ephemeral_array_service.d.ts.map +1 -0
  10. package/dest/contract_function_simulator/ephemeral_array_service.js +78 -0
  11. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +3 -4
  12. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts.map +1 -1
  13. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +3 -6
  14. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts +1 -1
  15. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.js +1 -1
  16. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +1 -1
  17. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -1
  18. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +3 -4
  19. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  20. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +3 -6
  21. package/dest/contract_function_simulator/oracle/interfaces.d.ts +31 -19
  22. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  23. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +1 -1
  24. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -1
  25. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +28 -24
  26. package/dest/contract_function_simulator/oracle/oracle.d.ts +50 -19
  27. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  28. package/dest/contract_function_simulator/oracle/oracle.js +177 -41
  29. package/dest/contract_function_simulator/oracle/private_execution.js +1 -1
  30. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +7 -11
  31. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  32. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +16 -9
  33. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +61 -38
  34. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  35. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +210 -92
  36. package/dest/contract_function_simulator/pick_notes.d.ts +1 -1
  37. package/dest/contract_function_simulator/pick_notes.d.ts.map +1 -1
  38. package/dest/contract_function_simulator/pick_notes.js +9 -2
  39. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts +1 -1
  40. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts.map +1 -1
  41. package/dest/contract_function_simulator/proxied_contract_data_source.js +3 -0
  42. package/dest/contract_logging.d.ts +9 -4
  43. package/dest/contract_logging.d.ts.map +1 -1
  44. package/dest/contract_logging.js +21 -6
  45. package/dest/contract_sync/contract_sync_service.d.ts +6 -5
  46. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  47. package/dest/contract_sync/contract_sync_service.js +44 -37
  48. package/dest/contract_sync/helpers.d.ts +2 -3
  49. package/dest/contract_sync/helpers.d.ts.map +1 -1
  50. package/dest/contract_sync/helpers.js +7 -2
  51. package/dest/debug/pxe_debug_utils.d.ts +3 -3
  52. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  53. package/dest/entrypoints/client/bundle/index.d.ts +1 -2
  54. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  55. package/dest/entrypoints/client/bundle/index.js +0 -1
  56. package/dest/entrypoints/client/bundle/utils.d.ts +2 -2
  57. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  58. package/dest/entrypoints/client/bundle/utils.js +2 -2
  59. package/dest/entrypoints/client/lazy/index.d.ts +1 -2
  60. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  61. package/dest/entrypoints/client/lazy/index.js +0 -1
  62. package/dest/entrypoints/client/lazy/utils.d.ts +2 -2
  63. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  64. package/dest/entrypoints/client/lazy/utils.js +2 -2
  65. package/dest/entrypoints/pxe_creation_options.d.ts +3 -1
  66. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  67. package/dest/entrypoints/pxe_creation_options.js +3 -1
  68. package/dest/entrypoints/server/index.d.ts +2 -3
  69. package/dest/entrypoints/server/index.d.ts.map +1 -1
  70. package/dest/entrypoints/server/index.js +1 -2
  71. package/dest/entrypoints/server/utils.d.ts +2 -2
  72. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  73. package/dest/entrypoints/server/utils.js +2 -2
  74. package/dest/events/event_service.d.ts +3 -2
  75. package/dest/events/event_service.d.ts.map +1 -1
  76. package/dest/events/event_service.js +16 -4
  77. package/dest/logs/log_service.d.ts +5 -8
  78. package/dest/logs/log_service.d.ts.map +1 -1
  79. package/dest/logs/log_service.js +24 -37
  80. package/dest/messages/message_context_service.d.ts +3 -3
  81. package/dest/messages/message_context_service.d.ts.map +1 -1
  82. package/dest/messages/message_context_service.js +3 -3
  83. package/dest/notes/note_service.d.ts +4 -5
  84. package/dest/notes/note_service.d.ts.map +1 -1
  85. package/dest/notes/note_service.js +14 -5
  86. package/dest/notes_filter.d.ts +2 -3
  87. package/dest/notes_filter.d.ts.map +1 -1
  88. package/dest/oracle_version.d.ts +4 -3
  89. package/dest/oracle_version.d.ts.map +1 -1
  90. package/dest/oracle_version.js +20 -10
  91. package/dest/pxe.d.ts +4 -5
  92. package/dest/pxe.d.ts.map +1 -1
  93. package/dest/pxe.js +12 -6
  94. package/dest/storage/capsule_store/capsule_service.d.ts +21 -0
  95. package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -0
  96. package/dest/storage/capsule_store/capsule_service.js +50 -0
  97. package/dest/storage/capsule_store/capsule_store.d.ts +9 -9
  98. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  99. package/dest/storage/capsule_store/capsule_store.js +33 -28
  100. package/dest/storage/capsule_store/index.d.ts +2 -1
  101. package/dest/storage/capsule_store/index.d.ts.map +1 -1
  102. package/dest/storage/capsule_store/index.js +1 -0
  103. package/dest/storage/metadata.d.ts +1 -1
  104. package/dest/storage/metadata.js +1 -1
  105. package/dest/storage/note_store/note_store.d.ts +1 -1
  106. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  107. package/dest/storage/note_store/note_store.js +2 -2
  108. package/package.json +16 -16
  109. package/src/bin/check_oracle_version.ts +4 -4
  110. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  111. package/src/contract_function_simulator/contract_function_simulator.ts +17 -7
  112. package/src/contract_function_simulator/ephemeral_array_service.ts +110 -0
  113. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -4
  114. package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +1 -1
  115. package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +1 -1
  116. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -4
  117. package/src/contract_function_simulator/oracle/interfaces.ts +46 -17
  118. package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +20 -58
  119. package/src/contract_function_simulator/oracle/oracle.ts +242 -36
  120. package/src/contract_function_simulator/oracle/private_execution.ts +1 -1
  121. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +19 -14
  122. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +351 -118
  123. package/src/contract_function_simulator/pick_notes.ts +9 -2
  124. package/src/contract_function_simulator/proxied_contract_data_source.ts +8 -1
  125. package/src/contract_logging.ts +18 -5
  126. package/src/contract_sync/contract_sync_service.ts +77 -59
  127. package/src/contract_sync/helpers.ts +4 -4
  128. package/src/debug/pxe_debug_utils.ts +3 -3
  129. package/src/entrypoints/client/bundle/index.ts +0 -1
  130. package/src/entrypoints/client/bundle/utils.ts +2 -3
  131. package/src/entrypoints/client/lazy/index.ts +0 -1
  132. package/src/entrypoints/client/lazy/utils.ts +2 -3
  133. package/src/entrypoints/pxe_creation_options.ts +7 -0
  134. package/src/entrypoints/server/index.ts +1 -2
  135. package/src/entrypoints/server/utils.ts +2 -3
  136. package/src/events/event_service.ts +17 -4
  137. package/src/logs/log_service.ts +52 -78
  138. package/src/messages/message_context_service.ts +3 -4
  139. package/src/notes/note_service.ts +18 -8
  140. package/src/notes_filter.ts +1 -3
  141. package/src/oracle_version.ts +20 -10
  142. package/src/pxe.ts +17 -12
  143. package/src/storage/capsule_store/capsule_service.ts +90 -0
  144. package/src/storage/capsule_store/capsule_store.ts +34 -26
  145. package/src/storage/capsule_store/index.ts +1 -0
  146. package/src/storage/metadata.ts +1 -1
  147. package/src/storage/note_store/note_store.ts +2 -5
  148. package/dest/access_scopes.d.ts +0 -9
  149. package/dest/access_scopes.d.ts.map +0 -1
  150. package/dest/access_scopes.js +0 -6
  151. package/dest/contract_function_simulator/noir-structs/message_tx_context.d.ts +0 -16
  152. package/dest/contract_function_simulator/noir-structs/message_tx_context.d.ts.map +0 -1
  153. package/dest/contract_function_simulator/noir-structs/message_tx_context.js +0 -57
  154. package/src/access_scopes.ts +0 -9
  155. package/src/contract_function_simulator/noir-structs/message_tx_context.ts +0 -55
@@ -15,30 +15,30 @@ 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
- import type { AccessScopes } from '../../access_scopes.js';
25
- import { createContractLogger, logContractMessage } from '../../contract_logging.js';
24
+ import { createContractLogger, logContractMessage, stripAztecnrLogPrefix } from '../../contract_logging.js';
25
+ import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
26
26
  import { EventService } from '../../events/event_service.js';
27
27
  import { LogService } from '../../logs/log_service.js';
28
28
  import { MessageContextService } from '../../messages/message_context_service.js';
29
29
  import { NoteService } from '../../notes/note_service.js';
30
- import { ORACLE_VERSION } from '../../oracle_version.js';
30
+ import { ORACLE_VERSION_MAJOR } from '../../oracle_version.js';
31
31
  import type { AddressStore } from '../../storage/address_store/address_store.js';
32
- import type { CapsuleStore } from '../../storage/capsule_store/capsule_store.js';
32
+ import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
33
33
  import type { ContractStore } from '../../storage/contract_store/contract_store.js';
34
34
  import type { NoteStore } from '../../storage/note_store/note_store.js';
35
35
  import type { PrivateEventStore } from '../../storage/private_event_store/private_event_store.js';
36
36
  import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
37
37
  import type { SenderAddressBookStore } from '../../storage/tagging_store/sender_address_book_store.js';
38
+ import { EphemeralArrayService } from '../ephemeral_array_service.js';
38
39
  import { EventValidationRequest } from '../noir-structs/event_validation_request.js';
39
40
  import { LogRetrievalRequest } from '../noir-structs/log_retrieval_request.js';
40
41
  import { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
41
- import { MessageTxContext } from '../noir-structs/message_tx_context.js';
42
42
  import { NoteValidationRequest } from '../noir-structs/note_validation_request.js';
43
43
  import { UtilityContext } from '../noir-structs/utility_context.js';
44
44
  import { pickNotes } from '../pick_notes.js';
@@ -59,12 +59,13 @@ export type UtilityExecutionOracleArgs = {
59
59
  aztecNode: AztecNode;
60
60
  recipientTaggingStore: RecipientTaggingStore;
61
61
  senderAddressBookStore: SenderAddressBookStore;
62
- capsuleStore: CapsuleStore;
62
+ capsuleService: CapsuleService;
63
63
  privateEventStore: PrivateEventStore;
64
64
  messageContextService: MessageContextService;
65
+ contractSyncService: ContractSyncService;
65
66
  jobId: string;
66
67
  log?: ReturnType<typeof createLogger>;
67
- scopes: AccessScopes;
68
+ scopes: AztecAddress[];
68
69
  };
69
70
 
70
71
  /**
@@ -75,7 +76,12 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
75
76
  isUtility = true as const;
76
77
 
77
78
  private contractLogger: Logger | undefined;
79
+ private aztecnrLogger: Logger | undefined;
78
80
  private offchainEffects: OffchainEffect[] = [];
81
+ private readonly ephemeralArrayService = new EphemeralArrayService();
82
+
83
+ // We store oracle version to be able to show a nice error message when an oracle handler is missing.
84
+ private contractOracleVersion: { major: number; minor: number } | undefined;
79
85
 
80
86
  protected readonly contractAddress: AztecAddress;
81
87
  protected readonly authWitnesses: AuthWitness[];
@@ -88,12 +94,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
88
94
  protected readonly aztecNode: AztecNode;
89
95
  protected readonly recipientTaggingStore: RecipientTaggingStore;
90
96
  protected readonly senderAddressBookStore: SenderAddressBookStore;
91
- protected readonly capsuleStore: CapsuleStore;
97
+ protected readonly capsuleService: CapsuleService;
92
98
  protected readonly privateEventStore: PrivateEventStore;
93
99
  protected readonly messageContextService: MessageContextService;
100
+ protected readonly contractSyncService: ContractSyncService;
94
101
  protected readonly jobId: string;
95
102
  protected logger: ReturnType<typeof createLogger>;
96
- protected readonly scopes: AccessScopes;
103
+ protected readonly scopes: AztecAddress[];
97
104
 
98
105
  constructor(args: UtilityExecutionOracleArgs) {
99
106
  this.contractAddress = args.contractAddress;
@@ -107,15 +114,16 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
107
114
  this.aztecNode = args.aztecNode;
108
115
  this.recipientTaggingStore = args.recipientTaggingStore;
109
116
  this.senderAddressBookStore = args.senderAddressBookStore;
110
- this.capsuleStore = args.capsuleStore;
117
+ this.capsuleService = args.capsuleService;
111
118
  this.privateEventStore = args.privateEventStore;
112
119
  this.messageContextService = args.messageContextService;
120
+ this.contractSyncService = args.contractSyncService;
113
121
  this.jobId = args.jobId;
114
122
  this.logger = args.log ?? createLogger('simulator:client_view_context');
115
123
  this.scopes = args.scopes;
116
124
  }
117
125
 
118
- public assertCompatibleOracleVersion(version: number): void {
126
+ public assertCompatibleOracleVersion(major: number, minor: number): void {
119
127
  // TODO(F-416): Remove this hack on v5 when protocol contracts are redeployed.
120
128
  // Protocol contracts/canonical contracts shipped with committed bytecode that cannot be changed. Assert they use
121
129
  // the expected pinned version or the current one. We want to allow for both the pinned and the current versions
@@ -123,17 +131,36 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
123
131
  // pinned contracts (like e.g. next)
124
132
  const LEGACY_ORACLE_VERSION = 12;
125
133
  if (isProtocolContract(this.contractAddress)) {
126
- if (version !== LEGACY_ORACLE_VERSION && version !== ORACLE_VERSION) {
134
+ if (major !== LEGACY_ORACLE_VERSION && major !== ORACLE_VERSION_MAJOR) {
135
+ const hint =
136
+ major > ORACLE_VERSION_MAJOR
137
+ ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
138
+ : '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.';
127
139
  throw new Error(
128
- `Expected legacy oracle version ${LEGACY_ORACLE_VERSION} or current oracle version ${ORACLE_VERSION} for alpha payload contract at ${this.contractAddress}, got ${version}.`,
140
+ `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})`,
129
141
  );
130
142
  }
143
+ this.contractOracleVersion = { major, minor };
131
144
  return;
132
145
  }
133
146
 
134
- if (version !== ORACLE_VERSION) {
135
- throw new Error(`Incompatible oracle version. Expected version ${ORACLE_VERSION}, got ${version}.`);
147
+ if (major !== ORACLE_VERSION_MAJOR) {
148
+ const hint =
149
+ major > ORACLE_VERSION_MAJOR
150
+ ? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
151
+ : '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.';
152
+ throw new Error(
153
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
154
+ );
136
155
  }
156
+
157
+ // Major matches - store both major and minor for later diagnostics (e.g. when an oracle is not found)
158
+ this.contractOracleVersion = { major, minor };
159
+ }
160
+
161
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
162
+ public nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
163
+ return this.contractOracleVersion;
137
164
  }
138
165
 
139
166
  public getRandomField(): Fr {
@@ -152,33 +179,32 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
152
179
  * @throws If scopes are defined and the account is not in the scopes.
153
180
  */
154
181
  public async getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
155
- // If scopes are defined, check that the key belongs to an account in the scopes.
156
- if (this.scopes !== 'ALL_SCOPES' && this.scopes.length > 0) {
157
- let hasAccess = false;
158
- for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
159
- if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
160
- hasAccess = true;
161
- }
162
- }
163
- if (!hasAccess) {
164
- throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
182
+ let hasAccess = false;
183
+ for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
184
+ if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
185
+ hasAccess = true;
165
186
  }
166
187
  }
188
+ if (!hasAccess) {
189
+ throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
190
+ }
167
191
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
168
192
  }
169
193
 
170
194
  /**
171
195
  * Fetches the index and sibling path of a leaf at a given block from the note hash tree.
172
- * @param anchorBlockHash - The hash of a block that contains the note hash tree root in which to find the membership
173
- * witness.
196
+ * @param blockHash - The hash of a block that contains the note hash tree root in which to find the
197
+ * membership witness.
174
198
  * @param noteHash - The note hash to find in the note hash tree.
175
199
  * @returns The membership witness containing the leaf index and sibling path
176
200
  */
177
201
  public getNoteHashMembershipWitness(
178
- anchorBlockHash: BlockHash,
202
+ blockHash: BlockHash,
179
203
  noteHash: Fr,
180
204
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
181
- return this.aztecNode.getNoteHashMembershipWitness(anchorBlockHash, noteHash);
205
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
206
+ this.aztecNode.getNoteHashMembershipWitness(blockHash, noteHash),
207
+ );
182
208
  }
183
209
 
184
210
  /**
@@ -187,16 +213,21 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
187
213
  * Block hashes are the leaves of the archive tree. Each time a new block is added to the chain,
188
214
  * its block hash is appended as a new leaf to the archive tree.
189
215
  *
190
- * @param anchorBlockHash - The hash of a block that contains the archive tree root in which to find the membership
216
+ * @param referenceBlockHash - The hash of a block that contains the archive tree root in which to find the membership
191
217
  * witness.
192
218
  * @param blockHash - The block hash to find in the archive tree.
193
219
  * @returns The membership witness containing the leaf index and sibling path
194
220
  */
195
221
  public getBlockHashMembershipWitness(
196
- anchorBlockHash: BlockHash,
222
+ referenceBlockHash: BlockHash,
197
223
  blockHash: BlockHash,
198
224
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
199
- return this.aztecNode.getBlockHashMembershipWitness(anchorBlockHash, blockHash);
225
+ // Note that we validate that the reference block hash is at or before the anchor block - we don't test the block
226
+ // hash at all. If the block hash did not exist by the reference block hash, then the node will not return the
227
+ // membership witness as there is none.
228
+ return this.#queryWithBlockHashNotAfterAnchor(referenceBlockHash, () =>
229
+ this.aztecNode.getBlockHashMembershipWitness(referenceBlockHash, blockHash),
230
+ );
200
231
  }
201
232
 
202
233
  /**
@@ -209,7 +240,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
209
240
  blockHash: BlockHash,
210
241
  nullifier: Fr,
211
242
  ): Promise<NullifierMembershipWitness | undefined> {
212
- return this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier);
243
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
244
+ this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier),
245
+ );
213
246
  }
214
247
 
215
248
  /**
@@ -225,7 +258,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
225
258
  blockHash: BlockHash,
226
259
  nullifier: Fr,
227
260
  ): Promise<NullifierMembershipWitness | undefined> {
228
- return this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier);
261
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
262
+ this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier),
263
+ );
229
264
  }
230
265
 
231
266
  /**
@@ -235,7 +270,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
235
270
  * @returns - The witness
236
271
  */
237
272
  public getPublicDataWitness(blockHash: BlockHash, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
238
- return this.aztecNode.getPublicDataWitness(blockHash, leafSlot);
273
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
274
+ this.aztecNode.getPublicDataWitness(blockHash, leafSlot),
275
+ );
239
276
  }
240
277
 
241
278
  /**
@@ -258,7 +295,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
258
295
  * @param account - The account address.
259
296
  * @returns The public keys and partial address, or `undefined` if the account is not registered.
260
297
  */
261
- public async tryGetPublicKeysAndPartialAddress(
298
+ public async getPublicKeysAndPartialAddress(
262
299
  account: AztecAddress,
263
300
  ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> {
264
301
  const completeAddress = await this.addressStore.getCompleteAddress(account);
@@ -364,7 +401,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
364
401
  * @param innerNullifier - The inner nullifier.
365
402
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
366
403
  */
367
- public async checkNullifierExists(innerNullifier: Fr) {
404
+ public async doesNullifierExist(innerNullifier: Fr) {
368
405
  const [nullifier, anchorBlockHash] = await Promise.all([
369
406
  siloNullifier(this.contractAddress, innerNullifier!),
370
407
  this.anchorBlockHeader.hash(),
@@ -376,7 +413,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
376
413
  }
377
414
 
378
415
  /**
379
- * Fetches a message from the executionStore, given its key.
416
+ * Returns the membership witness of an un-nullified L1 to L2 message.
380
417
  * @param contractAddress - Address of a contract by which the message was emitted.
381
418
  * @param messageHash - Hash of the message.
382
419
  * @param secret - Secret used to compute a nullifier.
@@ -389,6 +426,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
389
426
  contractAddress,
390
427
  messageHash,
391
428
  secret,
429
+ await this.anchorBlockHeader.hash(),
392
430
  );
393
431
 
394
432
  return new MessageLoadOracleInputs(messageIndex, siblingPath);
@@ -401,29 +439,31 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
401
439
  * @param startStorageSlot - The starting storage slot.
402
440
  * @param numberOfElements - Number of elements to read from the starting storage slot.
403
441
  */
404
- public async storageRead(
442
+ public getFromPublicStorage(
405
443
  blockHash: BlockHash,
406
444
  contractAddress: AztecAddress,
407
445
  startStorageSlot: Fr,
408
446
  numberOfElements: number,
409
447
  ) {
410
- const slots = Array(numberOfElements)
411
- .fill(0)
412
- .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
448
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, async () => {
449
+ const slots = Array(numberOfElements)
450
+ .fill(0)
451
+ .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
413
452
 
414
- const values = await Promise.all(
415
- slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
416
- );
453
+ const values = await Promise.all(
454
+ slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
455
+ );
417
456
 
418
- this.logger.debug(
419
- `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
420
- );
457
+ this.logger.debug(
458
+ `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
459
+ );
421
460
 
422
- return values;
461
+ return values;
462
+ });
423
463
  }
424
464
 
425
465
  /**
426
- * Returns a per-contract logger whose output is prefixed with `contract_log::<name>(<addrAbbrev>)`.
466
+ * Returns a per-contract logger whose output is prefixed with `contract:<name>(<addrAbbrev>)`.
427
467
  */
428
468
  async #getContractLogger(): Promise<Logger> {
429
469
  if (!this.contractLogger) {
@@ -432,45 +472,78 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
432
472
  this.contractLogger = await createContractLogger(
433
473
  this.contractAddress,
434
474
  addr => this.contractStore.getDebugContractName(addr),
475
+ 'user',
435
476
  { instanceId: this.jobId },
436
477
  );
437
478
  }
438
479
  return this.contractLogger;
439
480
  }
440
481
 
482
+ /**
483
+ * Returns a per-contract logger whose output is prefixed with `aztecnr:<name>(<addrAbbrev>)`.
484
+ */
485
+ async #getAztecnrLogger(): Promise<Logger> {
486
+ if (!this.aztecnrLogger) {
487
+ // Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
488
+ // to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
489
+ this.aztecnrLogger = await createContractLogger(
490
+ this.contractAddress,
491
+ addr => this.contractStore.getDebugContractName(addr),
492
+ 'aztecnr',
493
+ { instanceId: this.jobId },
494
+ );
495
+ }
496
+ return this.aztecnrLogger;
497
+ }
498
+
441
499
  public async log(level: number, message: string, fields: Fr[]): Promise<void> {
442
500
  if (!LogLevels[level]) {
443
501
  throw new Error(`Invalid log level: ${level}`);
444
502
  }
445
- const logger = await this.#getContractLogger();
446
- logContractMessage(logger, LogLevels[level], message, fields);
503
+
504
+ const { kind, message: strippedMessage } = stripAztecnrLogPrefix(message);
505
+
506
+ const logger = kind == 'aztecnr' ? await this.#getAztecnrLogger() : await this.#getContractLogger();
507
+ logContractMessage(logger, LogLevels[level], strippedMessage, fields);
447
508
  }
448
509
 
449
- public async fetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
450
- const logService = new LogService(
510
+ // Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
511
+ public async getPendingTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr, scope: AztecAddress) {
512
+ const logService = this.#createLogService();
513
+ const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
514
+ await this.capsuleService.appendToCapsuleArray(
515
+ this.contractAddress,
516
+ pendingTaggedLogArrayBaseSlot,
517
+ logs.map(log => log.toFields()),
518
+ this.jobId,
519
+ scope,
520
+ );
521
+ }
522
+
523
+ /** Fetches pending tagged logs into a freshly allocated ephemeral array and returns its base slot. */
524
+ public async getPendingTaggedLogsV2(scope: AztecAddress): Promise<Fr> {
525
+ const logService = this.#createLogService();
526
+ const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
527
+ return this.ephemeralArrayService.newArray(logs.map(log => log.toFields()));
528
+ }
529
+
530
+ #createLogService(): LogService {
531
+ return new LogService(
451
532
  this.aztecNode,
452
533
  this.anchorBlockHeader,
453
534
  this.keyStore,
454
- this.capsuleStore,
455
535
  this.recipientTaggingStore,
456
536
  this.senderAddressBookStore,
457
537
  this.addressStore,
458
538
  this.jobId,
459
539
  this.logger.getBindings(),
460
540
  );
461
-
462
- await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
463
541
  }
464
542
 
465
543
  /**
466
- * Validates all note and event validation requests enqueued via `enqueue_note_for_validation` and
467
- * `enqueue_event_for_validation`, inserting them into the note database and event store respectively, making them
468
- * queryable via `get_notes` and `getPrivateEvents`.
544
+ * Legacy: validates note/event requests stored in capsule arrays.
469
545
  *
470
- * This automatically clears both validation request queues, so no further work needs to be done by the caller.
471
- * @param contractAddress - The address of the contract that the logs are tagged for.
472
- * @param noteValidationRequestsArrayBaseSlot - The base slot of capsule array containing note validation requests.
473
- * @param eventValidationRequestsArrayBaseSlot - The base slot of capsule array containing event validation requests.
546
+ * Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
474
547
  */
475
548
  public async validateAndStoreEnqueuedNotesAndEvents(
476
549
  contractAddress: AztecAddress,
@@ -478,22 +551,78 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
478
551
  eventValidationRequestsArrayBaseSlot: Fr,
479
552
  maxNotePackedLen: number,
480
553
  maxEventSerializedLen: number,
554
+ scope: AztecAddress,
481
555
  ) {
482
556
  // TODO(#10727): allow other contracts to store notes
483
557
  if (!this.contractAddress.equals(contractAddress)) {
484
558
  throw new Error(`Got a note validation request from ${contractAddress}, expected ${this.contractAddress}`);
485
559
  }
486
560
 
487
- // We read all note and event validation requests and process them all concurrently. This makes the process much
488
- // faster as we don't need to wait for the network round-trip.
489
561
  const noteValidationRequests = (
490
- await this.capsuleStore.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, this.jobId)
562
+ await this.capsuleService.readCapsuleArray(
563
+ contractAddress,
564
+ noteValidationRequestsArrayBaseSlot,
565
+ this.jobId,
566
+ scope,
567
+ )
491
568
  ).map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
492
569
 
493
570
  const eventValidationRequests = (
494
- await this.capsuleStore.readCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, this.jobId)
571
+ await this.capsuleService.readCapsuleArray(
572
+ contractAddress,
573
+ eventValidationRequestsArrayBaseSlot,
574
+ this.jobId,
575
+ scope,
576
+ )
495
577
  ).map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
496
578
 
579
+ await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
580
+
581
+ await this.capsuleService.setCapsuleArray(
582
+ contractAddress,
583
+ noteValidationRequestsArrayBaseSlot,
584
+ [],
585
+ this.jobId,
586
+ scope,
587
+ );
588
+ await this.capsuleService.setCapsuleArray(
589
+ contractAddress,
590
+ eventValidationRequestsArrayBaseSlot,
591
+ [],
592
+ this.jobId,
593
+ scope,
594
+ );
595
+ }
596
+
597
+ public async validateAndStoreEnqueuedNotesAndEventsV2(
598
+ noteValidationRequestsArrayBaseSlot: Fr,
599
+ eventValidationRequestsArrayBaseSlot: Fr,
600
+ maxNotePackedLen: number,
601
+ maxEventSerializedLen: number,
602
+ scope: AztecAddress,
603
+ ) {
604
+ const noteValidationRequests = this.ephemeralArrayService
605
+ .readArrayAt(noteValidationRequestsArrayBaseSlot)
606
+ .map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
607
+
608
+ const eventValidationRequests = this.ephemeralArrayService
609
+ .readArrayAt(eventValidationRequestsArrayBaseSlot)
610
+ .map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
611
+
612
+ await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
613
+ }
614
+
615
+ /**
616
+ * Dispatches note and event validation requests to the service layer.
617
+ *
618
+ * This function is an auxiliary to support legacy (capsule backed) and new (ephemeral array backed) versions of the
619
+ * `validateAndStoreEnqueuedNotesAndEvents` oracle.
620
+ */
621
+ async #processValidationRequests(
622
+ noteValidationRequests: NoteValidationRequest[],
623
+ eventValidationRequests: EventValidationRequest[],
624
+ scope: AztecAddress,
625
+ ) {
497
626
  const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
498
627
  const noteStorePromises = noteValidationRequests.map(request =>
499
628
  noteService.validateAndStoreNote(
@@ -506,7 +635,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
506
635
  request.noteHash,
507
636
  request.nullifier,
508
637
  request.txHash,
509
- request.recipient,
638
+ scope,
510
639
  ),
511
640
  );
512
641
 
@@ -519,21 +648,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
519
648
  request.serializedEvent,
520
649
  request.eventCommitment,
521
650
  request.txHash,
522
- request.recipient,
651
+ scope,
523
652
  ),
524
653
  );
525
654
 
526
655
  await Promise.all([...noteStorePromises, ...eventStorePromises]);
527
-
528
- // Requests are cleared once we're done.
529
- await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, [], this.jobId);
530
- await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, [], this.jobId);
531
656
  }
532
657
 
533
- public async bulkRetrieveLogs(
658
+ public async getLogsByTag(
534
659
  contractAddress: AztecAddress,
535
660
  logRetrievalRequestsArrayBaseSlot: Fr,
536
661
  logRetrievalResponsesArrayBaseSlot: Fr,
662
+ scope: AztecAddress,
537
663
  ) {
538
664
  // TODO(#10727): allow other contracts to process partial notes
539
665
  if (!this.contractAddress.equals(contractAddress)) {
@@ -543,48 +669,63 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
543
669
  // We read all log retrieval requests and process them all concurrently. This makes the process much faster as we
544
670
  // don't need to wait for the network round-trip.
545
671
  const logRetrievalRequests = (
546
- await this.capsuleStore.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId)
672
+ await this.capsuleService.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId, scope)
547
673
  ).map(LogRetrievalRequest.fromFields);
548
674
 
549
- const logService = new LogService(
550
- this.aztecNode,
551
- this.anchorBlockHeader,
552
- this.keyStore,
553
- this.capsuleStore,
554
- this.recipientTaggingStore,
555
- this.senderAddressBookStore,
556
- this.addressStore,
557
- this.jobId,
558
- this.logger.getBindings(),
559
- );
560
-
561
- const maybeLogRetrievalResponses = await logService.bulkRetrieveLogs(logRetrievalRequests);
675
+ const logService = this.#createLogService();
676
+ const maybeLogRetrievalResponses = await logService.fetchLogsByTag(contractAddress, logRetrievalRequests);
562
677
 
563
678
  // Requests are cleared once we're done.
564
- await this.capsuleStore.setCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, [], this.jobId);
679
+ await this.capsuleService.setCapsuleArray(
680
+ contractAddress,
681
+ logRetrievalRequestsArrayBaseSlot,
682
+ [],
683
+ this.jobId,
684
+ scope,
685
+ );
565
686
 
566
687
  // The responses are stored as Option<LogRetrievalResponse> in a second CapsuleArray.
567
- await this.capsuleStore.setCapsuleArray(
688
+ await this.capsuleService.setCapsuleArray(
568
689
  contractAddress,
569
690
  logRetrievalResponsesArrayBaseSlot,
570
691
  maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption),
571
692
  this.jobId,
693
+ scope,
572
694
  );
573
695
  }
574
696
 
575
- public async utilityResolveMessageContexts(
697
+ public async getLogsByTagV2(requestArrayBaseSlot: Fr): Promise<Fr> {
698
+ const logRetrievalRequests = this.ephemeralArrayService
699
+ .readArrayAt(requestArrayBaseSlot)
700
+ .map(LogRetrievalRequest.fromFields);
701
+ const logService = this.#createLogService();
702
+
703
+ const maybeLogRetrievalResponses = await logService.fetchLogsByTag(this.contractAddress, logRetrievalRequests);
704
+
705
+ return this.ephemeralArrayService.newArray(maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption));
706
+ }
707
+
708
+ // Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
709
+ public async getMessageContextsByTxHash(
576
710
  contractAddress: AztecAddress,
577
711
  messageContextRequestsArrayBaseSlot: Fr,
578
712
  messageContextResponsesArrayBaseSlot: Fr,
713
+ scope: AztecAddress,
579
714
  ) {
580
715
  try {
581
716
  if (!this.contractAddress.equals(contractAddress)) {
582
717
  throw new Error(`Got a message context request from ${contractAddress}, expected ${this.contractAddress}`);
583
718
  }
584
- const requestCapsules = await this.capsuleStore.readCapsuleArray(
719
+
720
+ // TODO(@mverzilli): this is a prime example of where using an ephemeral array would make much more sense, we don't
721
+ // need scopes here, we just need a bit of shared memory to cross boundaries between Noir and TS.
722
+ // At the same time, we don't want to allow any global scope access other than where backwards compatibility
723
+ // forces us to. Hence we need the scope here to be artificial.
724
+ const requestCapsules = await this.capsuleService.readCapsuleArray(
585
725
  contractAddress,
586
726
  messageContextRequestsArrayBaseSlot,
587
727
  this.jobId,
728
+ scope,
588
729
  );
589
730
 
590
731
  const txHashes = requestCapsules.map((fields, i) => {
@@ -596,81 +737,153 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
596
737
  return fields[0];
597
738
  });
598
739
 
599
- const maybeMessageContexts = await this.messageContextService.resolveMessageContexts(
740
+ const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
600
741
  txHashes,
601
742
  this.anchorBlockHeader.getBlockNumber(),
602
743
  );
603
744
 
604
745
  // Leave response in response capsule array.
605
- await this.capsuleStore.setCapsuleArray(
746
+ await this.capsuleService.setCapsuleArray(
606
747
  contractAddress,
607
748
  messageContextResponsesArrayBaseSlot,
608
- maybeMessageContexts.map(MessageTxContext.toSerializedOption),
749
+ maybeMessageContexts.map(MessageContext.toSerializedOption),
609
750
  this.jobId,
751
+ scope,
610
752
  );
611
753
  } finally {
612
- await this.capsuleStore.setCapsuleArray(contractAddress, messageContextRequestsArrayBaseSlot, [], this.jobId);
754
+ await this.capsuleService.setCapsuleArray(
755
+ contractAddress,
756
+ messageContextRequestsArrayBaseSlot,
757
+ [],
758
+ this.jobId,
759
+ scope,
760
+ );
613
761
  }
614
762
  }
615
763
 
616
- public storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
764
+ /** Reads tx hash requests from an ephemeral array, resolves their contexts, and returns the response slot. */
765
+ public async getMessageContextsByTxHashV2(requestArrayBaseSlot: Fr): Promise<Fr> {
766
+ const requestFields = this.ephemeralArrayService.readArrayAt(requestArrayBaseSlot);
767
+
768
+ const txHashes = requestFields.map((fields, i) => {
769
+ if (fields.length !== 1) {
770
+ throw new Error(
771
+ `Malformed message context request at index ${i}: expected 1 field (tx hash), got ${fields.length}`,
772
+ );
773
+ }
774
+ return fields[0];
775
+ });
776
+
777
+ const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
778
+ txHashes,
779
+ this.anchorBlockHeader.getBlockNumber(),
780
+ );
781
+
782
+ return this.ephemeralArrayService.newArray(maybeMessageContexts.map(MessageContext.toSerializedOption));
783
+ }
784
+
785
+ public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
617
786
  if (!contractAddress.equals(this.contractAddress)) {
618
787
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
619
788
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
620
789
  }
621
- this.capsuleStore.storeCapsule(this.contractAddress, slot, capsule, this.jobId);
622
- return Promise.resolve();
790
+ this.capsuleService.setCapsule(contractAddress, slot, capsule, this.jobId, scope);
623
791
  }
624
792
 
625
- public async loadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
793
+ public getCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): Promise<Fr[] | null> {
626
794
  if (!contractAddress.equals(this.contractAddress)) {
627
795
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
628
796
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
629
797
  }
630
- return (
631
- // TODO(#12425): On the following line, the pertinent capsule gets overshadowed by the transient one. Tackle this.
632
- this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ??
633
- (await this.capsuleStore.loadCapsule(this.contractAddress, slot, this.jobId))
634
- );
798
+ return this.capsuleService.getCapsule(contractAddress, slot, this.jobId, scope, this.capsules);
635
799
  }
636
800
 
637
- public deleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
801
+ public deleteCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): void {
638
802
  if (!contractAddress.equals(this.contractAddress)) {
639
803
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
640
804
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
641
805
  }
642
- this.capsuleStore.deleteCapsule(this.contractAddress, slot, this.jobId);
643
- return Promise.resolve();
806
+ this.capsuleService.deleteCapsule(contractAddress, slot, this.jobId, scope);
644
807
  }
645
808
 
646
- public copyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
809
+ public copyCapsule(
810
+ contractAddress: AztecAddress,
811
+ srcSlot: Fr,
812
+ dstSlot: Fr,
813
+ numEntries: number,
814
+ scope: AztecAddress,
815
+ ): Promise<void> {
647
816
  if (!contractAddress.equals(this.contractAddress)) {
648
817
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
649
818
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
650
819
  }
651
- return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
820
+ return this.capsuleService.copyCapsule(contractAddress, srcSlot, dstSlot, numEntries, this.jobId, scope);
821
+ }
822
+
823
+ /**
824
+ * Clears cached sync state for a contract for a set of scopes, forcing re-sync on the next query so that newly
825
+ * stored notes or events are discovered.
826
+ */
827
+ public setContractSyncCacheInvalid(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
828
+ if (!contractAddress.equals(this.contractAddress)) {
829
+ throw new Error(`Contract ${this.contractAddress} cannot invalidate sync cache of ${contractAddress}`);
830
+ }
831
+ this.contractSyncService.invalidateContractForScopes(contractAddress, scopes);
652
832
  }
653
833
 
654
834
  // TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
655
- public aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
835
+ public decryptAes128(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
656
836
  const aes128 = new Aes128();
657
837
  return aes128.decryptBufferCBC(ciphertext, iv, symKey);
658
838
  }
659
839
 
660
840
  /**
661
- * Retrieves the shared secret for a given address and ephemeral public key.
841
+ * Retrieves the app-siloed shared secret for a given address and ephemeral public key.
662
842
  * @param address - The address to get the secret for.
663
843
  * @param ephPk - The ephemeral public key to get the secret for.
664
- * @returns The secret for the given address.
844
+ * @param contractAddress - The contract address for app-siloing (validated against execution context).
845
+ * @returns The app-siloed shared secret as a Field.
665
846
  */
666
- public async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
667
- // TODO(#12656): return an app-siloed secret
847
+ public async getSharedSecret(address: AztecAddress, ephPk: Point, contractAddress: AztecAddress): Promise<Fr> {
848
+ if (!contractAddress.equals(this.contractAddress)) {
849
+ throw new Error(
850
+ `getSharedSecret called with contract address ${contractAddress}, expected ${this.contractAddress}`,
851
+ );
852
+ }
668
853
  const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
669
854
  const ivskM = await this.keyStore.getMasterSecretKey(
670
855
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
671
856
  );
672
857
  const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
673
- return deriveEcdhSharedSecret(addressSecret, ephPk);
858
+ return deriveAppSiloedSharedSecret(addressSecret, ephPk, this.contractAddress);
859
+ }
860
+
861
+ public pushEphemeral(slot: Fr, elements: Fr[]): number {
862
+ return this.ephemeralArrayService.push(slot, elements);
863
+ }
864
+
865
+ public popEphemeral(slot: Fr): Fr[] {
866
+ return this.ephemeralArrayService.pop(slot);
867
+ }
868
+
869
+ public getEphemeral(slot: Fr, index: number): Fr[] {
870
+ return this.ephemeralArrayService.get(slot, index);
871
+ }
872
+
873
+ public setEphemeral(slot: Fr, index: number, elements: Fr[]): void {
874
+ this.ephemeralArrayService.set(slot, index, elements);
875
+ }
876
+
877
+ public getEphemeralLen(slot: Fr): number {
878
+ return this.ephemeralArrayService.len(slot);
879
+ }
880
+
881
+ public removeEphemeral(slot: Fr, index: number): void {
882
+ this.ephemeralArrayService.remove(slot, index);
883
+ }
884
+
885
+ public clearEphemeral(slot: Fr): void {
886
+ this.ephemeralArrayService.clear(slot);
674
887
  }
675
888
 
676
889
  public emitOffchainEffect(data: Fr[]): Promise<void> {
@@ -682,4 +895,24 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
682
895
  public getOffchainEffects(): OffchainEffect[] {
683
896
  return this.offchainEffects;
684
897
  }
898
+
899
+ /** Runs a query concurrently with a validation that the block hash is not ahead of the anchor block. */
900
+ async #queryWithBlockHashNotAfterAnchor<T>(blockHash: BlockHash, query: () => Promise<T>): Promise<T> {
901
+ const [response] = await Promise.all([
902
+ query(),
903
+ (async () => {
904
+ const header = await this.aztecNode.getBlockHeader(blockHash);
905
+ if (!header) {
906
+ throw new Error(`Could not find block header for block hash ${blockHash}`);
907
+ }
908
+
909
+ if (header.getBlockNumber() > this.anchorBlockHeader.getBlockNumber()) {
910
+ throw new Error(
911
+ `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()}).`,
912
+ );
913
+ }
914
+ })(),
915
+ ]);
916
+ return response;
917
+ }
685
918
  }