@aztec/pxe 4.0.0-devnet.2-patch.3 → 4.0.0-devnet.3-patch.0

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 (168) hide show
  1. package/dest/config/package_info.js +1 -1
  2. package/dest/contract_function_simulator/contract_function_simulator.d.ts +10 -5
  3. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  4. package/dest/contract_function_simulator/contract_function_simulator.js +35 -12
  5. package/dest/contract_function_simulator/execution_tagging_index_cache.d.ts +7 -7
  6. package/dest/contract_function_simulator/execution_tagging_index_cache.d.ts.map +1 -1
  7. package/dest/contract_function_simulator/execution_tagging_index_cache.js +19 -11
  8. package/dest/contract_function_simulator/index.d.ts +2 -1
  9. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  10. package/dest/contract_function_simulator/index.js +1 -0
  11. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +3 -5
  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 +7 -9
  14. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +1 -1
  15. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts.map +1 -1
  16. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -3
  17. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +3 -6
  18. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  19. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +5 -10
  20. package/dest/contract_function_simulator/oracle/interfaces.d.ts +50 -45
  21. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  22. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +9 -0
  23. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -0
  24. package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +38 -0
  25. package/dest/contract_function_simulator/oracle/oracle.d.ts +64 -44
  26. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  27. package/dest/contract_function_simulator/oracle/oracle.js +187 -97
  28. package/dest/contract_function_simulator/oracle/private_execution.js +5 -3
  29. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +23 -49
  30. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  31. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +50 -81
  32. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +66 -47
  33. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  34. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +190 -99
  35. package/dest/contract_logging.d.ts +27 -0
  36. package/dest/contract_logging.d.ts.map +1 -0
  37. package/dest/contract_logging.js +38 -0
  38. package/dest/contract_sync/contract_sync_service.d.ts +6 -5
  39. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  40. package/dest/contract_sync/contract_sync_service.js +44 -37
  41. package/dest/contract_sync/helpers.d.ts +2 -3
  42. package/dest/contract_sync/helpers.d.ts.map +1 -1
  43. package/dest/contract_sync/helpers.js +7 -2
  44. package/dest/debug/pxe_debug_utils.d.ts +3 -3
  45. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  46. package/dest/debug/pxe_debug_utils.js +4 -4
  47. package/dest/entrypoints/client/bundle/index.d.ts +2 -2
  48. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  49. package/dest/entrypoints/client/bundle/index.js +1 -1
  50. package/dest/entrypoints/client/lazy/index.d.ts +2 -2
  51. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  52. package/dest/entrypoints/client/lazy/index.js +1 -1
  53. package/dest/entrypoints/server/index.d.ts +1 -2
  54. package/dest/entrypoints/server/index.d.ts.map +1 -1
  55. package/dest/entrypoints/server/index.js +0 -1
  56. package/dest/events/event_service.d.ts +3 -2
  57. package/dest/events/event_service.d.ts.map +1 -1
  58. package/dest/events/event_service.js +16 -4
  59. package/dest/logs/log_service.d.ts +6 -7
  60. package/dest/logs/log_service.d.ts.map +1 -1
  61. package/dest/logs/log_service.js +34 -32
  62. package/dest/messages/message_context_service.d.ts +17 -0
  63. package/dest/messages/message_context_service.d.ts.map +1 -0
  64. package/dest/messages/message_context_service.js +36 -0
  65. package/dest/notes/note_service.d.ts +4 -5
  66. package/dest/notes/note_service.d.ts.map +1 -1
  67. package/dest/notes/note_service.js +14 -5
  68. package/dest/notes_filter.d.ts +2 -3
  69. package/dest/notes_filter.d.ts.map +1 -1
  70. package/dest/oracle_version.d.ts +2 -2
  71. package/dest/oracle_version.js +3 -3
  72. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts +4 -3
  73. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts.map +1 -1
  74. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +125 -64
  75. package/dest/private_kernel/hints/test_utils.d.ts +122 -0
  76. package/dest/private_kernel/hints/test_utils.d.ts.map +1 -0
  77. package/dest/private_kernel/hints/test_utils.js +203 -0
  78. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  79. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  80. package/dest/private_kernel/private_kernel_execution_prover.js +13 -5
  81. package/dest/pxe.d.ts +14 -12
  82. package/dest/pxe.d.ts.map +1 -1
  83. package/dest/pxe.js +56 -35
  84. package/dest/storage/capsule_store/capsule_service.d.ts +21 -0
  85. package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -0
  86. package/dest/storage/capsule_store/capsule_service.js +50 -0
  87. package/dest/storage/capsule_store/capsule_store.d.ts +9 -9
  88. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  89. package/dest/storage/capsule_store/capsule_store.js +33 -28
  90. package/dest/storage/capsule_store/index.d.ts +2 -1
  91. package/dest/storage/capsule_store/index.d.ts.map +1 -1
  92. package/dest/storage/capsule_store/index.js +1 -0
  93. package/dest/storage/metadata.d.ts +1 -1
  94. package/dest/storage/metadata.js +1 -1
  95. package/dest/storage/note_store/note_store.d.ts +1 -1
  96. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  97. package/dest/storage/note_store/note_store.js +2 -2
  98. package/dest/storage/tagging_store/recipient_tagging_store.d.ts +6 -6
  99. package/dest/storage/tagging_store/recipient_tagging_store.d.ts.map +1 -1
  100. package/dest/storage/tagging_store/sender_tagging_store.d.ts +29 -28
  101. package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
  102. package/dest/storage/tagging_store/sender_tagging_store.js +141 -115
  103. package/dest/tagging/index.d.ts +3 -3
  104. package/dest/tagging/index.d.ts.map +1 -1
  105. package/dest/tagging/index.js +1 -1
  106. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +4 -5
  107. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  108. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +3 -3
  109. package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts +6 -7
  110. package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts.map +1 -1
  111. package/dest/tagging/recipient_sync/utils/load_logs_for_range.js +12 -11
  112. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts +4 -8
  113. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts.map +1 -1
  114. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +13 -7
  115. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts +4 -3
  116. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts.map +1 -1
  117. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.js +20 -10
  118. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +5 -7
  119. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
  120. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +36 -24
  121. package/package.json +16 -16
  122. package/src/config/package_info.ts +1 -1
  123. package/src/contract_function_simulator/contract_function_simulator.ts +55 -24
  124. package/src/contract_function_simulator/execution_tagging_index_cache.ts +19 -14
  125. package/src/contract_function_simulator/index.ts +1 -0
  126. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +8 -8
  127. package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +1 -4
  128. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +3 -9
  129. package/src/contract_function_simulator/oracle/interfaces.ts +63 -54
  130. package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +98 -0
  131. package/src/contract_function_simulator/oracle/oracle.ts +223 -139
  132. package/src/contract_function_simulator/oracle/private_execution.ts +4 -4
  133. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +58 -103
  134. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +320 -123
  135. package/src/contract_logging.ts +52 -0
  136. package/src/contract_sync/contract_sync_service.ts +77 -59
  137. package/src/contract_sync/helpers.ts +4 -4
  138. package/src/debug/pxe_debug_utils.ts +7 -7
  139. package/src/entrypoints/client/bundle/index.ts +1 -1
  140. package/src/entrypoints/client/lazy/index.ts +1 -1
  141. package/src/entrypoints/server/index.ts +0 -1
  142. package/src/events/event_service.ts +17 -4
  143. package/src/logs/log_service.ts +72 -52
  144. package/src/messages/message_context_service.ts +44 -0
  145. package/src/notes/note_service.ts +18 -8
  146. package/src/notes_filter.ts +1 -3
  147. package/src/oracle_version.ts +3 -3
  148. package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +157 -110
  149. package/src/private_kernel/hints/test_utils.ts +325 -0
  150. package/src/private_kernel/private_kernel_execution_prover.ts +13 -6
  151. package/src/pxe.ts +84 -45
  152. package/src/storage/capsule_store/capsule_service.ts +90 -0
  153. package/src/storage/capsule_store/capsule_store.ts +34 -26
  154. package/src/storage/capsule_store/index.ts +1 -0
  155. package/src/storage/metadata.ts +1 -1
  156. package/src/storage/note_store/note_store.ts +2 -5
  157. package/src/storage/tagging_store/recipient_tagging_store.ts +9 -5
  158. package/src/storage/tagging_store/sender_tagging_store.ts +185 -138
  159. package/src/tagging/index.ts +2 -2
  160. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +3 -6
  161. package/src/tagging/recipient_sync/utils/load_logs_for_range.ts +10 -15
  162. package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +23 -10
  163. package/src/tagging/sender_sync/utils/get_status_change_of_pending.ts +26 -11
  164. package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +27 -26
  165. package/dest/access_scopes.d.ts +0 -9
  166. package/dest/access_scopes.d.ts.map +0 -1
  167. package/dest/access_scopes.js +0 -6
  168. package/src/access_scopes.ts +0 -9
@@ -3,30 +3,33 @@ import type { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Aes128 } from '@aztec/foundation/crypto/aes128';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { Point } from '@aztec/foundation/curves/grumpkin';
6
- import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
6
+ 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
+ import { isProtocolContract } from '@aztec/protocol-contracts';
9
10
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
10
11
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
11
12
  import { BlockHash } from '@aztec/stdlib/block';
12
- import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
13
+ import type { CompleteAddress, ContractInstance, PartialAddress } from '@aztec/stdlib/contract';
13
14
  import { siloNullifier } from '@aztec/stdlib/hash';
14
15
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
15
16
  import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
16
- import { computeAddressSecret } from '@aztec/stdlib/keys';
17
- import { deriveEcdhSharedSecret } from '@aztec/stdlib/logs';
17
+ import { type PublicKeys, computeAddressSecret } from '@aztec/stdlib/keys';
18
+ import { MessageContext, deriveAppSiloedSharedSecret } from '@aztec/stdlib/logs';
18
19
  import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
19
20
  import type { NoteStatus } from '@aztec/stdlib/note';
20
21
  import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
21
- import type { BlockHeader, Capsule } from '@aztec/stdlib/tx';
22
+ import type { BlockHeader, Capsule, OffchainEffect } from '@aztec/stdlib/tx';
22
23
 
23
- import type { AccessScopes } from '../../access_scopes.js';
24
+ import { createContractLogger, logContractMessage, stripAztecnrLogPrefix } from '../../contract_logging.js';
25
+ import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
24
26
  import { EventService } from '../../events/event_service.js';
25
27
  import { LogService } from '../../logs/log_service.js';
28
+ import { MessageContextService } from '../../messages/message_context_service.js';
26
29
  import { NoteService } from '../../notes/note_service.js';
27
30
  import { ORACLE_VERSION } from '../../oracle_version.js';
28
31
  import type { AddressStore } from '../../storage/address_store/address_store.js';
29
- import type { CapsuleStore } from '../../storage/capsule_store/capsule_store.js';
32
+ import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
30
33
  import type { ContractStore } from '../../storage/contract_store/contract_store.js';
31
34
  import type { NoteStore } from '../../storage/note_store/note_store.js';
32
35
  import type { PrivateEventStore } from '../../storage/private_event_store/private_event_store.js';
@@ -55,11 +58,13 @@ export type UtilityExecutionOracleArgs = {
55
58
  aztecNode: AztecNode;
56
59
  recipientTaggingStore: RecipientTaggingStore;
57
60
  senderAddressBookStore: SenderAddressBookStore;
58
- capsuleStore: CapsuleStore;
61
+ capsuleService: CapsuleService;
59
62
  privateEventStore: PrivateEventStore;
63
+ messageContextService: MessageContextService;
64
+ contractSyncService: ContractSyncService;
60
65
  jobId: string;
61
66
  log?: ReturnType<typeof createLogger>;
62
- scopes: AccessScopes;
67
+ scopes: AztecAddress[];
63
68
  };
64
69
 
65
70
  /**
@@ -70,6 +75,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
70
75
  isUtility = true as const;
71
76
 
72
77
  private contractLogger: Logger | undefined;
78
+ private aztecnrLogger: Logger | undefined;
79
+ private offchainEffects: OffchainEffect[] = [];
73
80
 
74
81
  protected readonly contractAddress: AztecAddress;
75
82
  protected readonly authWitnesses: AuthWitness[];
@@ -82,11 +89,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
82
89
  protected readonly aztecNode: AztecNode;
83
90
  protected readonly recipientTaggingStore: RecipientTaggingStore;
84
91
  protected readonly senderAddressBookStore: SenderAddressBookStore;
85
- protected readonly capsuleStore: CapsuleStore;
92
+ protected readonly capsuleService: CapsuleService;
86
93
  protected readonly privateEventStore: PrivateEventStore;
94
+ protected readonly messageContextService: MessageContextService;
95
+ protected readonly contractSyncService: ContractSyncService;
87
96
  protected readonly jobId: string;
88
- protected log: ReturnType<typeof createLogger>;
89
- protected readonly scopes: AccessScopes;
97
+ protected logger: ReturnType<typeof createLogger>;
98
+ protected readonly scopes: AztecAddress[];
90
99
 
91
100
  constructor(args: UtilityExecutionOracleArgs) {
92
101
  this.contractAddress = args.contractAddress;
@@ -100,24 +109,51 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
100
109
  this.aztecNode = args.aztecNode;
101
110
  this.recipientTaggingStore = args.recipientTaggingStore;
102
111
  this.senderAddressBookStore = args.senderAddressBookStore;
103
- this.capsuleStore = args.capsuleStore;
112
+ this.capsuleService = args.capsuleService;
104
113
  this.privateEventStore = args.privateEventStore;
114
+ this.messageContextService = args.messageContextService;
115
+ this.contractSyncService = args.contractSyncService;
105
116
  this.jobId = args.jobId;
106
- this.log = args.log ?? createLogger('simulator:client_view_context');
117
+ this.logger = args.log ?? createLogger('simulator:client_view_context');
107
118
  this.scopes = args.scopes;
108
119
  }
109
120
 
110
- public utilityAssertCompatibleOracleVersion(version: number): void {
121
+ public assertCompatibleOracleVersion(version: number): void {
122
+ // TODO(F-416): Remove this hack on v5 when protocol contracts are redeployed.
123
+ // Protocol contracts/canonical contracts shipped with committed bytecode that cannot be changed. Assert they use
124
+ // the expected pinned version or the current one. We want to allow for both the pinned and the current versions
125
+ // because we want this code to work with both the pinned and unpinned version since some branches do not have the
126
+ // pinned contracts (like e.g. next)
127
+ const LEGACY_ORACLE_VERSION = 12;
128
+ if (isProtocolContract(this.contractAddress)) {
129
+ if (version !== LEGACY_ORACLE_VERSION && version !== ORACLE_VERSION) {
130
+ const hint =
131
+ version > ORACLE_VERSION
132
+ ? '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
+ : '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
+ 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})`,
136
+ );
137
+ }
138
+ return;
139
+ }
140
+
111
141
  if (version !== ORACLE_VERSION) {
112
- throw new Error(`Incompatible oracle version. Expected version ${ORACLE_VERSION}, got ${version}.`);
142
+ const hint =
143
+ version > ORACLE_VERSION
144
+ ? '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
+ : '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
+ throw new Error(
147
+ `Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle version ${ORACLE_VERSION}, got ${version})`,
148
+ );
113
149
  }
114
150
  }
115
151
 
116
- public utilityGetRandomField(): Fr {
152
+ public getRandomField(): Fr {
117
153
  return Fr.random();
118
154
  }
119
155
 
120
- public utilityGetUtilityContext(): UtilityContext {
156
+ public getUtilityContext(): UtilityContext {
121
157
  return new UtilityContext(this.anchorBlockHeader, this.contractAddress);
122
158
  }
123
159
 
@@ -128,34 +164,33 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
128
164
  * @throws If the keys are not registered in the key store.
129
165
  * @throws If scopes are defined and the account is not in the scopes.
130
166
  */
131
- public async utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
132
- // If scopes are defined, check that the key belongs to an account in the scopes.
133
- if (this.scopes !== 'ALL_SCOPES' && this.scopes.length > 0) {
134
- let hasAccess = false;
135
- for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
136
- if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
137
- hasAccess = true;
138
- }
139
- }
140
- if (!hasAccess) {
141
- throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
167
+ public async getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
168
+ let hasAccess = false;
169
+ for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
170
+ if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
171
+ hasAccess = true;
142
172
  }
143
173
  }
174
+ if (!hasAccess) {
175
+ throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
176
+ }
144
177
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
145
178
  }
146
179
 
147
180
  /**
148
181
  * Fetches the index and sibling path of a leaf at a given block from the note hash tree.
149
- * @param anchorBlockHash - The hash of a block that contains the note hash tree root in which to find the membership
150
- * witness.
182
+ * @param blockHash - The hash of a block that contains the note hash tree root in which to find the
183
+ * membership witness.
151
184
  * @param noteHash - The note hash to find in the note hash tree.
152
185
  * @returns The membership witness containing the leaf index and sibling path
153
186
  */
154
- public utilityGetNoteHashMembershipWitness(
155
- anchorBlockHash: BlockHash,
187
+ public getNoteHashMembershipWitness(
188
+ blockHash: BlockHash,
156
189
  noteHash: Fr,
157
190
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
158
- return this.aztecNode.getNoteHashMembershipWitness(anchorBlockHash, noteHash);
191
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
192
+ this.aztecNode.getNoteHashMembershipWitness(blockHash, noteHash),
193
+ );
159
194
  }
160
195
 
161
196
  /**
@@ -164,16 +199,21 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
164
199
  * Block hashes are the leaves of the archive tree. Each time a new block is added to the chain,
165
200
  * its block hash is appended as a new leaf to the archive tree.
166
201
  *
167
- * @param anchorBlockHash - The hash of a block that contains the archive tree root in which to find the membership
202
+ * @param referenceBlockHash - The hash of a block that contains the archive tree root in which to find the membership
168
203
  * witness.
169
204
  * @param blockHash - The block hash to find in the archive tree.
170
205
  * @returns The membership witness containing the leaf index and sibling path
171
206
  */
172
- public utilityGetBlockHashMembershipWitness(
173
- anchorBlockHash: BlockHash,
207
+ public getBlockHashMembershipWitness(
208
+ referenceBlockHash: BlockHash,
174
209
  blockHash: BlockHash,
175
210
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
176
- return this.aztecNode.getBlockHashMembershipWitness(anchorBlockHash, blockHash);
211
+ // Note that we validate that the reference block hash is at or before the anchor block - we don't test the block
212
+ // hash at all. If the block hash did not exist by the reference block hash, then the node will not return the
213
+ // membership witness as there is none.
214
+ return this.#queryWithBlockHashNotAfterAnchor(referenceBlockHash, () =>
215
+ this.aztecNode.getBlockHashMembershipWitness(referenceBlockHash, blockHash),
216
+ );
177
217
  }
178
218
 
179
219
  /**
@@ -182,11 +222,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
182
222
  * @param nullifier - Nullifier we try to find witness for.
183
223
  * @returns The nullifier membership witness (if found).
184
224
  */
185
- public utilityGetNullifierMembershipWitness(
225
+ public getNullifierMembershipWitness(
186
226
  blockHash: BlockHash,
187
227
  nullifier: Fr,
188
228
  ): Promise<NullifierMembershipWitness | undefined> {
189
- return this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier);
229
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
230
+ this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier),
231
+ );
190
232
  }
191
233
 
192
234
  /**
@@ -198,11 +240,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
198
240
  * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
199
241
  * we are trying to prove non-inclusion for.
200
242
  */
201
- public utilityGetLowNullifierMembershipWitness(
243
+ public getLowNullifierMembershipWitness(
202
244
  blockHash: BlockHash,
203
245
  nullifier: Fr,
204
246
  ): Promise<NullifierMembershipWitness | undefined> {
205
- return this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier);
247
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
248
+ this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier),
249
+ );
206
250
  }
207
251
 
208
252
  /**
@@ -211,8 +255,10 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
211
255
  * @param leafSlot - The slot of the public data tree to get the witness for.
212
256
  * @returns - The witness
213
257
  */
214
- public utilityGetPublicDataWitness(blockHash: BlockHash, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
215
- return this.aztecNode.getPublicDataWitness(blockHash, leafSlot);
258
+ public getPublicDataWitness(blockHash: BlockHash, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
259
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
260
+ this.aztecNode.getPublicDataWitness(blockHash, leafSlot),
261
+ );
216
262
  }
217
263
 
218
264
  /**
@@ -220,7 +266,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
220
266
  * @param blockNumber - The number of a block of which to get the block header.
221
267
  * @returns Block extracted from a block with block number `blockNumber`.
222
268
  */
223
- public async utilityGetBlockHeader(blockNumber: BlockNumber): Promise<BlockHeader | undefined> {
269
+ public async getBlockHeader(blockNumber: BlockNumber): Promise<BlockHeader | undefined> {
224
270
  const anchorBlockNumber = this.anchorBlockHeader.getBlockNumber();
225
271
  if (blockNumber > anchorBlockNumber) {
226
272
  throw new Error(`Block number ${blockNumber} is higher than current block ${anchorBlockNumber}`);
@@ -231,12 +277,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
231
277
  }
232
278
 
233
279
  /**
234
- * Retrieve the complete address associated to a given address.
280
+ * Retrieve the public keys and partial address associated to a given address.
235
281
  * @param account - The account address.
236
- * @returns A complete address associated with the input address, or `undefined` if not registered.
282
+ * @returns The public keys and partial address, or `undefined` if the account is not registered.
237
283
  */
238
- public utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress | undefined> {
239
- return this.addressStore.getCompleteAddress(account);
284
+ public async getPublicKeysAndPartialAddress(
285
+ account: AztecAddress,
286
+ ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> {
287
+ const completeAddress = await this.addressStore.getCompleteAddress(account);
288
+ if (!completeAddress) {
289
+ return undefined;
290
+ }
291
+ return { publicKeys: completeAddress.publicKeys, partialAddress: completeAddress.partialAddress };
240
292
  }
241
293
 
242
294
  protected async getCompleteAddressOrFail(account: AztecAddress): Promise<CompleteAddress> {
@@ -255,11 +307,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
255
307
  * @param address - Address.
256
308
  * @returns A contract instance.
257
309
  */
258
- public utilityGetContractInstance(address: AztecAddress): Promise<ContractInstance> {
259
- return this.getContractInstance(address);
260
- }
261
-
262
- protected async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
310
+ public async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
263
311
  const instance = await this.contractStore.getContractInstance(address);
264
312
  if (!instance) {
265
313
  throw new Error(`No contract instance found for address ${address.toString()}`);
@@ -273,7 +321,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
273
321
  * @param messageHash - Hash of the message to authenticate.
274
322
  * @returns Authentication witness for the requested message hash.
275
323
  */
276
- public utilityGetAuthWitness(messageHash: Fr): Promise<Fr[] | undefined> {
324
+ public getAuthWitness(messageHash: Fr): Promise<Fr[] | undefined> {
277
325
  return Promise.resolve(this.authWitnesses.find(w => w.requestHash.equals(messageHash))?.witness);
278
326
  }
279
327
 
@@ -299,7 +347,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
299
347
  * @param status - The status of notes to fetch.
300
348
  * @returns Array of note data.
301
349
  */
302
- public async utilityGetNotes(
350
+ public async getNotes(
303
351
  owner: AztecAddress | undefined,
304
352
  storageSlot: Fr,
305
353
  numSelects: number,
@@ -339,7 +387,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
339
387
  * @param innerNullifier - The inner nullifier.
340
388
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
341
389
  */
342
- public async utilityCheckNullifierExists(innerNullifier: Fr) {
390
+ public async doesNullifierExist(innerNullifier: Fr) {
343
391
  const [nullifier, anchorBlockHash] = await Promise.all([
344
392
  siloNullifier(this.contractAddress, innerNullifier!),
345
393
  this.anchorBlockHeader.hash(),
@@ -351,19 +399,20 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
351
399
  }
352
400
 
353
401
  /**
354
- * Fetches a message from the executionStore, given its key.
402
+ * Returns the membership witness of an un-nullified L1 to L2 message.
355
403
  * @param contractAddress - Address of a contract by which the message was emitted.
356
404
  * @param messageHash - Hash of the message.
357
405
  * @param secret - Secret used to compute a nullifier.
358
406
  * @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
359
407
  * @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
360
408
  */
361
- public async utilityGetL1ToL2MembershipWitness(contractAddress: AztecAddress, messageHash: Fr, secret: Fr) {
409
+ public async getL1ToL2MembershipWitness(contractAddress: AztecAddress, messageHash: Fr, secret: Fr) {
362
410
  const [messageIndex, siblingPath] = await getNonNullifiedL1ToL2MessageWitness(
363
411
  this.aztecNode,
364
412
  contractAddress,
365
413
  messageHash,
366
414
  secret,
415
+ await this.anchorBlockHeader.hash(),
367
416
  );
368
417
 
369
418
  return new MessageLoadOracleInputs(messageIndex, siblingPath);
@@ -376,65 +425,88 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
376
425
  * @param startStorageSlot - The starting storage slot.
377
426
  * @param numberOfElements - Number of elements to read from the starting storage slot.
378
427
  */
379
- public async utilityStorageRead(
428
+ public getFromPublicStorage(
380
429
  blockHash: BlockHash,
381
430
  contractAddress: AztecAddress,
382
431
  startStorageSlot: Fr,
383
432
  numberOfElements: number,
384
433
  ) {
385
- const slots = Array(numberOfElements)
386
- .fill(0)
387
- .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
434
+ return this.#queryWithBlockHashNotAfterAnchor(blockHash, async () => {
435
+ const slots = Array(numberOfElements)
436
+ .fill(0)
437
+ .map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
388
438
 
389
- const values = await Promise.all(
390
- slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
391
- );
439
+ const values = await Promise.all(
440
+ slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
441
+ );
392
442
 
393
- this.log.debug(
394
- `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
395
- );
443
+ this.logger.debug(
444
+ `Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
445
+ );
396
446
 
397
- return values;
447
+ return values;
448
+ });
398
449
  }
399
450
 
400
451
  /**
401
- * Returns a per-contract logger whose output is prefixed with `contract_log::<name>(<addrAbbrev>)`.
452
+ * Returns a per-contract logger whose output is prefixed with `contract:<name>(<addrAbbrev>)`.
402
453
  */
403
454
  async #getContractLogger(): Promise<Logger> {
404
455
  if (!this.contractLogger) {
405
- const addrAbbrev = this.contractAddress.toString().slice(0, 10);
406
- const name = await this.contractStore.getDebugContractName(this.contractAddress);
407
- const module = name ? `contract_log::${name}(${addrAbbrev})` : `contract_log::${addrAbbrev}`;
408
456
  // Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
409
457
  // to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
410
- this.contractLogger = createLogger(module, { instanceId: this.jobId });
458
+ this.contractLogger = await createContractLogger(
459
+ this.contractAddress,
460
+ addr => this.contractStore.getDebugContractName(addr),
461
+ 'user',
462
+ { instanceId: this.jobId },
463
+ );
411
464
  }
412
465
  return this.contractLogger;
413
466
  }
414
467
 
415
- public async utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
468
+ /**
469
+ * Returns a per-contract logger whose output is prefixed with `aztecnr:<name>(<addrAbbrev>)`.
470
+ */
471
+ async #getAztecnrLogger(): Promise<Logger> {
472
+ if (!this.aztecnrLogger) {
473
+ // Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
474
+ // to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
475
+ this.aztecnrLogger = await createContractLogger(
476
+ this.contractAddress,
477
+ addr => this.contractStore.getDebugContractName(addr),
478
+ 'aztecnr',
479
+ { instanceId: this.jobId },
480
+ );
481
+ }
482
+ return this.aztecnrLogger;
483
+ }
484
+
485
+ public async log(level: number, message: string, fields: Fr[]): Promise<void> {
416
486
  if (!LogLevels[level]) {
417
487
  throw new Error(`Invalid log level: ${level}`);
418
488
  }
419
- const levelName = LogLevels[level];
420
- const logger = await this.#getContractLogger();
421
- logger[levelName](`${applyStringFormatting(message, fields)}`);
489
+
490
+ const { kind, message: strippedMessage } = stripAztecnrLogPrefix(message);
491
+
492
+ const logger = kind == 'aztecnr' ? await this.#getAztecnrLogger() : await this.#getContractLogger();
493
+ logContractMessage(logger, LogLevels[level], strippedMessage, fields);
422
494
  }
423
495
 
424
- public async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
496
+ public async getPendingTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr, scope: AztecAddress) {
425
497
  const logService = new LogService(
426
498
  this.aztecNode,
427
499
  this.anchorBlockHeader,
428
500
  this.keyStore,
429
- this.capsuleStore,
501
+ this.capsuleService,
430
502
  this.recipientTaggingStore,
431
503
  this.senderAddressBookStore,
432
504
  this.addressStore,
433
505
  this.jobId,
434
- this.log.getBindings(),
506
+ this.logger.getBindings(),
435
507
  );
436
508
 
437
- await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
509
+ await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, scope);
438
510
  }
439
511
 
440
512
  /**
@@ -447,10 +519,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
447
519
  * @param noteValidationRequestsArrayBaseSlot - The base slot of capsule array containing note validation requests.
448
520
  * @param eventValidationRequestsArrayBaseSlot - The base slot of capsule array containing event validation requests.
449
521
  */
450
- public async utilityValidateAndStoreEnqueuedNotesAndEvents(
522
+ public async validateAndStoreEnqueuedNotesAndEvents(
451
523
  contractAddress: AztecAddress,
452
524
  noteValidationRequestsArrayBaseSlot: Fr,
453
525
  eventValidationRequestsArrayBaseSlot: Fr,
526
+ maxNotePackedLen: number,
527
+ maxEventSerializedLen: number,
528
+ scope: AztecAddress,
454
529
  ) {
455
530
  // TODO(#10727): allow other contracts to store notes
456
531
  if (!this.contractAddress.equals(contractAddress)) {
@@ -460,12 +535,22 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
460
535
  // We read all note and event validation requests and process them all concurrently. This makes the process much
461
536
  // faster as we don't need to wait for the network round-trip.
462
537
  const noteValidationRequests = (
463
- await this.capsuleStore.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, this.jobId)
464
- ).map(NoteValidationRequest.fromFields);
538
+ await this.capsuleService.readCapsuleArray(
539
+ contractAddress,
540
+ noteValidationRequestsArrayBaseSlot,
541
+ this.jobId,
542
+ scope,
543
+ )
544
+ ).map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
465
545
 
466
546
  const eventValidationRequests = (
467
- await this.capsuleStore.readCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, this.jobId)
468
- ).map(EventValidationRequest.fromFields);
547
+ await this.capsuleService.readCapsuleArray(
548
+ contractAddress,
549
+ eventValidationRequestsArrayBaseSlot,
550
+ this.jobId,
551
+ scope,
552
+ )
553
+ ).map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
469
554
 
470
555
  const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
471
556
  const noteStorePromises = noteValidationRequests.map(request =>
@@ -479,7 +564,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
479
564
  request.noteHash,
480
565
  request.nullifier,
481
566
  request.txHash,
482
- request.recipient,
567
+ scope,
483
568
  ),
484
569
  );
485
570
 
@@ -492,21 +577,34 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
492
577
  request.serializedEvent,
493
578
  request.eventCommitment,
494
579
  request.txHash,
495
- request.recipient,
580
+ scope,
496
581
  ),
497
582
  );
498
583
 
499
584
  await Promise.all([...noteStorePromises, ...eventStorePromises]);
500
585
 
501
586
  // Requests are cleared once we're done.
502
- await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, [], this.jobId);
503
- await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, [], this.jobId);
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
+ );
504
601
  }
505
602
 
506
- public async utilityBulkRetrieveLogs(
603
+ public async getLogsByTag(
507
604
  contractAddress: AztecAddress,
508
605
  logRetrievalRequestsArrayBaseSlot: Fr,
509
606
  logRetrievalResponsesArrayBaseSlot: Fr,
607
+ scope: AztecAddress,
510
608
  ) {
511
609
  // TODO(#10727): allow other contracts to process partial notes
512
610
  if (!this.contractAddress.equals(contractAddress)) {
@@ -516,101 +614,200 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
516
614
  // We read all log retrieval requests and process them all concurrently. This makes the process much faster as we
517
615
  // don't need to wait for the network round-trip.
518
616
  const logRetrievalRequests = (
519
- await this.capsuleStore.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId)
617
+ await this.capsuleService.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId, scope)
520
618
  ).map(LogRetrievalRequest.fromFields);
521
619
 
522
620
  const logService = new LogService(
523
621
  this.aztecNode,
524
622
  this.anchorBlockHeader,
525
623
  this.keyStore,
526
- this.capsuleStore,
624
+ this.capsuleService,
527
625
  this.recipientTaggingStore,
528
626
  this.senderAddressBookStore,
529
627
  this.addressStore,
530
628
  this.jobId,
531
- this.log.getBindings(),
629
+ this.logger.getBindings(),
532
630
  );
533
631
 
534
- const maybeLogRetrievalResponses = await logService.bulkRetrieveLogs(logRetrievalRequests);
632
+ const maybeLogRetrievalResponses = await logService.fetchLogsByTag(contractAddress, logRetrievalRequests);
535
633
 
536
634
  // Requests are cleared once we're done.
537
- await this.capsuleStore.setCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, [], this.jobId);
635
+ await this.capsuleService.setCapsuleArray(
636
+ contractAddress,
637
+ logRetrievalRequestsArrayBaseSlot,
638
+ [],
639
+ this.jobId,
640
+ scope,
641
+ );
538
642
 
539
643
  // The responses are stored as Option<LogRetrievalResponse> in a second CapsuleArray.
540
- await this.capsuleStore.setCapsuleArray(
644
+ await this.capsuleService.setCapsuleArray(
541
645
  contractAddress,
542
646
  logRetrievalResponsesArrayBaseSlot,
543
647
  maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption),
544
648
  this.jobId,
649
+ scope,
545
650
  );
546
651
  }
547
652
 
548
- public utilityStoreCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
653
+ public async getMessageContextsByTxHash(
654
+ contractAddress: AztecAddress,
655
+ messageContextRequestsArrayBaseSlot: Fr,
656
+ messageContextResponsesArrayBaseSlot: Fr,
657
+ scope: AztecAddress,
658
+ ) {
659
+ try {
660
+ if (!this.contractAddress.equals(contractAddress)) {
661
+ throw new Error(`Got a message context request from ${contractAddress}, expected ${this.contractAddress}`);
662
+ }
663
+
664
+ // TODO(@mverzilli): this is a prime example of where using a volatile array would make much more sense, we don't
665
+ // need scopes here, we just need a bit of shared memory to cross boundaries between Noir and TS.
666
+ // At the same time, we don't want to allow any global scope access other than where backwards compatibility
667
+ // forces us to. Hence we need the scope here to be artificial.
668
+ const requestCapsules = await this.capsuleService.readCapsuleArray(
669
+ contractAddress,
670
+ messageContextRequestsArrayBaseSlot,
671
+ this.jobId,
672
+ scope,
673
+ );
674
+
675
+ const txHashes = requestCapsules.map((fields, i) => {
676
+ if (fields.length !== 1) {
677
+ throw new Error(
678
+ `Malformed message context request at index ${i}: expected 1 field (tx hash), got ${fields.length}`,
679
+ );
680
+ }
681
+ return fields[0];
682
+ });
683
+
684
+ const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
685
+ txHashes,
686
+ this.anchorBlockHeader.getBlockNumber(),
687
+ );
688
+
689
+ // Leave response in response capsule array.
690
+ await this.capsuleService.setCapsuleArray(
691
+ contractAddress,
692
+ messageContextResponsesArrayBaseSlot,
693
+ maybeMessageContexts.map(MessageContext.toSerializedOption),
694
+ this.jobId,
695
+ scope,
696
+ );
697
+ } finally {
698
+ await this.capsuleService.setCapsuleArray(
699
+ contractAddress,
700
+ messageContextRequestsArrayBaseSlot,
701
+ [],
702
+ this.jobId,
703
+ scope,
704
+ );
705
+ }
706
+ }
707
+
708
+ public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
549
709
  if (!contractAddress.equals(this.contractAddress)) {
550
710
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
551
711
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
552
712
  }
553
- this.capsuleStore.storeCapsule(this.contractAddress, slot, capsule, this.jobId);
554
- return Promise.resolve();
713
+ this.capsuleService.setCapsule(contractAddress, slot, capsule, this.jobId, scope);
555
714
  }
556
715
 
557
- public async utilityLoadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
716
+ public getCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): Promise<Fr[] | null> {
558
717
  if (!contractAddress.equals(this.contractAddress)) {
559
718
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
560
719
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
561
720
  }
562
- return (
563
- // TODO(#12425): On the following line, the pertinent capsule gets overshadowed by the transient one. Tackle this.
564
- this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ??
565
- (await this.capsuleStore.loadCapsule(this.contractAddress, slot, this.jobId))
566
- );
721
+ return this.capsuleService.getCapsule(contractAddress, slot, this.jobId, scope, this.capsules);
567
722
  }
568
723
 
569
- public utilityDeleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
724
+ public deleteCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): void {
570
725
  if (!contractAddress.equals(this.contractAddress)) {
571
726
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
572
727
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
573
728
  }
574
- this.capsuleStore.deleteCapsule(this.contractAddress, slot, this.jobId);
575
- return Promise.resolve();
729
+ this.capsuleService.deleteCapsule(contractAddress, slot, this.jobId, scope);
576
730
  }
577
731
 
578
- public utilityCopyCapsule(
732
+ public copyCapsule(
579
733
  contractAddress: AztecAddress,
580
734
  srcSlot: Fr,
581
735
  dstSlot: Fr,
582
736
  numEntries: number,
737
+ scope: AztecAddress,
583
738
  ): Promise<void> {
584
739
  if (!contractAddress.equals(this.contractAddress)) {
585
740
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
586
741
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
587
742
  }
588
- return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
743
+ return this.capsuleService.copyCapsule(contractAddress, srcSlot, dstSlot, numEntries, this.jobId, scope);
744
+ }
745
+
746
+ /**
747
+ * Clears cached sync state for a contract for a set of scopes, forcing re-sync on the next query so that newly
748
+ * stored notes or events are discovered.
749
+ */
750
+ public setContractSyncCacheInvalid(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
751
+ if (!contractAddress.equals(this.contractAddress)) {
752
+ throw new Error(`Contract ${this.contractAddress} cannot invalidate sync cache of ${contractAddress}`);
753
+ }
754
+ this.contractSyncService.invalidateContractForScopes(contractAddress, scopes);
589
755
  }
590
756
 
591
757
  // TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
592
- public utilityAes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
758
+ public decryptAes128(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
593
759
  const aes128 = new Aes128();
594
760
  return aes128.decryptBufferCBC(ciphertext, iv, symKey);
595
761
  }
596
762
 
597
763
  /**
598
- * Retrieves the shared secret for a given address and ephemeral public key.
764
+ * Retrieves the app-siloed shared secret for a given address and ephemeral public key.
599
765
  * @param address - The address to get the secret for.
600
766
  * @param ephPk - The ephemeral public key to get the secret for.
601
- * @returns The secret for the given address.
767
+ * @param contractAddress - The contract address for app-siloing (validated against execution context).
768
+ * @returns The app-siloed shared secret as a Field.
602
769
  */
603
- public utilityGetSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
604
- return this.getSharedSecret(address, ephPk);
605
- }
606
-
607
- protected async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
608
- // TODO(#12656): return an app-siloed secret
770
+ public async getSharedSecret(address: AztecAddress, ephPk: Point, contractAddress: AztecAddress): Promise<Fr> {
771
+ if (!contractAddress.equals(this.contractAddress)) {
772
+ throw new Error(
773
+ `getSharedSecret called with contract address ${contractAddress}, expected ${this.contractAddress}`,
774
+ );
775
+ }
609
776
  const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
610
777
  const ivskM = await this.keyStore.getMasterSecretKey(
611
778
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
612
779
  );
613
780
  const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
614
- return deriveEcdhSharedSecret(addressSecret, ephPk);
781
+ return deriveAppSiloedSharedSecret(addressSecret, ephPk, this.contractAddress);
782
+ }
783
+
784
+ public emitOffchainEffect(data: Fr[]): Promise<void> {
785
+ this.offchainEffects.push({ data, contractAddress: this.contractAddress });
786
+ return Promise.resolve();
787
+ }
788
+
789
+ /** Returns offchain effects collected during execution. */
790
+ public getOffchainEffects(): OffchainEffect[] {
791
+ return this.offchainEffects;
792
+ }
793
+
794
+ /** Runs a query concurrently with a validation that the block hash is not ahead of the anchor block. */
795
+ async #queryWithBlockHashNotAfterAnchor<T>(blockHash: BlockHash, query: () => Promise<T>): Promise<T> {
796
+ const [response] = await Promise.all([
797
+ query(),
798
+ (async () => {
799
+ const header = await this.aztecNode.getBlockHeader(blockHash);
800
+ if (!header) {
801
+ throw new Error(`Could not find block header for block hash ${blockHash}`);
802
+ }
803
+
804
+ if (header.getBlockNumber() > this.anchorBlockHeader.getBlockNumber()) {
805
+ throw new Error(
806
+ `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()}).`,
807
+ );
808
+ }
809
+ })(),
810
+ ]);
811
+ return response;
615
812
  }
616
813
  }