@aztec/pxe 0.0.1-commit.0c875d939 → 0.0.1-commit.0dc957cde

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