@aztec/pxe 0.0.1-commit.fcb71a6 → 0.0.1-commit.ff7989d6c

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 (266) hide show
  1. package/dest/access_scopes.d.ts +9 -0
  2. package/dest/access_scopes.d.ts.map +1 -0
  3. package/dest/access_scopes.js +6 -0
  4. package/dest/bin/check_oracle_version.js +1 -1
  5. package/dest/block_synchronizer/block_synchronizer.d.ts +13 -5
  6. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  7. package/dest/block_synchronizer/block_synchronizer.js +74 -20
  8. package/dest/config/index.d.ts +3 -1
  9. package/dest/config/index.d.ts.map +1 -1
  10. package/dest/config/index.js +17 -0
  11. package/dest/config/package_info.js +1 -1
  12. package/dest/contract_function_simulator/benchmarked_node.d.ts +9 -0
  13. package/dest/contract_function_simulator/benchmarked_node.d.ts.map +1 -0
  14. package/dest/contract_function_simulator/benchmarked_node.js +77 -0
  15. package/dest/contract_function_simulator/contract_function_simulator.d.ts +57 -34
  16. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/contract_function_simulator.js +197 -82
  18. package/dest/contract_function_simulator/execution_note_cache.d.ts +18 -9
  19. package/dest/contract_function_simulator/execution_note_cache.d.ts.map +1 -1
  20. package/dest/contract_function_simulator/execution_note_cache.js +45 -28
  21. package/dest/contract_function_simulator/index.d.ts +2 -2
  22. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  23. package/dest/contract_function_simulator/index.js +1 -1
  24. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +4 -3
  25. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts.map +1 -1
  26. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +7 -4
  27. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +3 -3
  28. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  29. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +2 -2
  30. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts +4 -10
  31. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts.map +1 -1
  32. package/dest/contract_function_simulator/noir-structs/utility_context.js +7 -18
  33. package/dest/contract_function_simulator/oracle/interfaces.d.ts +17 -13
  34. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  35. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts +3 -1
  36. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts.map +1 -1
  37. package/dest/contract_function_simulator/oracle/note_packing_utils.d.ts +6 -6
  38. package/dest/contract_function_simulator/oracle/note_packing_utils.d.ts.map +1 -1
  39. package/dest/contract_function_simulator/oracle/note_packing_utils.js +8 -8
  40. package/dest/contract_function_simulator/oracle/oracle.d.ts +12 -10
  41. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  42. package/dest/contract_function_simulator/oracle/oracle.js +67 -44
  43. package/dest/contract_function_simulator/oracle/private_execution.d.ts +2 -26
  44. package/dest/contract_function_simulator/oracle/private_execution.d.ts.map +1 -1
  45. package/dest/contract_function_simulator/oracle/private_execution.js +1 -37
  46. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +44 -50
  47. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  48. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +83 -54
  49. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +67 -33
  50. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  51. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +131 -110
  52. package/dest/contract_logging.d.ts +22 -0
  53. package/dest/contract_logging.d.ts.map +1 -0
  54. package/dest/contract_logging.js +23 -0
  55. package/dest/contract_sync/contract_sync_service.d.ts +43 -0
  56. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -0
  57. package/dest/contract_sync/contract_sync_service.js +97 -0
  58. package/dest/contract_sync/helpers.d.ts +29 -0
  59. package/dest/contract_sync/helpers.d.ts.map +1 -0
  60. package/dest/contract_sync/helpers.js +55 -0
  61. package/dest/debug/pxe_debug_utils.d.ts +24 -10
  62. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  63. package/dest/debug/pxe_debug_utils.js +28 -17
  64. package/dest/entrypoints/client/bundle/index.d.ts +4 -1
  65. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  66. package/dest/entrypoints/client/bundle/index.js +3 -0
  67. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  68. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  69. package/dest/entrypoints/client/bundle/utils.js +31 -8
  70. package/dest/entrypoints/client/lazy/index.d.ts +4 -1
  71. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  72. package/dest/entrypoints/client/lazy/index.js +3 -0
  73. package/dest/entrypoints/client/lazy/utils.d.ts +2 -2
  74. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  75. package/dest/entrypoints/client/lazy/utils.js +32 -9
  76. package/dest/entrypoints/pxe_creation_options.d.ts +5 -3
  77. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  78. package/dest/entrypoints/server/index.d.ts +5 -1
  79. package/dest/entrypoints/server/index.d.ts.map +1 -1
  80. package/dest/entrypoints/server/index.js +4 -0
  81. package/dest/entrypoints/server/utils.d.ts +1 -1
  82. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  83. package/dest/entrypoints/server/utils.js +39 -16
  84. package/dest/events/event_service.d.ts +6 -6
  85. package/dest/events/event_service.d.ts.map +1 -1
  86. package/dest/events/event_service.js +19 -22
  87. package/dest/events/private_event_filter_validator.d.ts +5 -5
  88. package/dest/events/private_event_filter_validator.d.ts.map +1 -1
  89. package/dest/events/private_event_filter_validator.js +5 -6
  90. package/dest/job_coordinator/job_coordinator.d.ts +75 -0
  91. package/dest/job_coordinator/job_coordinator.d.ts.map +1 -0
  92. package/dest/job_coordinator/job_coordinator.js +94 -0
  93. package/dest/logs/log_service.d.ts +8 -5
  94. package/dest/logs/log_service.d.ts.map +1 -1
  95. package/dest/logs/log_service.js +28 -30
  96. package/dest/notes/note_service.d.ts +10 -9
  97. package/dest/notes/note_service.d.ts.map +1 -1
  98. package/dest/notes/note_service.js +34 -38
  99. package/dest/notes_filter.d.ts +25 -0
  100. package/dest/notes_filter.d.ts.map +1 -0
  101. package/dest/notes_filter.js +4 -0
  102. package/dest/oracle_version.d.ts +3 -3
  103. package/dest/oracle_version.d.ts.map +1 -1
  104. package/dest/oracle_version.js +4 -3
  105. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts +4 -0
  106. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts.map +1 -0
  107. package/dest/private_kernel/hints/{compute_tx_include_by_timestamp.js → compute_tx_expiration_timestamp.js} +12 -12
  108. package/dest/private_kernel/hints/index.d.ts +3 -3
  109. package/dest/private_kernel/hints/index.d.ts.map +1 -1
  110. package/dest/private_kernel/hints/index.js +2 -2
  111. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts +28 -0
  112. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts.map +1 -0
  113. package/dest/private_kernel/hints/{build_private_kernel_reset_private_inputs.js → private_kernel_reset_private_inputs_builder.js} +16 -10
  114. package/dest/private_kernel/private_kernel_execution_prover.d.ts +3 -2
  115. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  116. package/dest/private_kernel/private_kernel_execution_prover.js +12 -13
  117. package/dest/private_kernel/private_kernel_oracle.d.ts +24 -24
  118. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  119. package/dest/private_kernel/private_kernel_oracle.js +94 -2
  120. package/dest/pxe.d.ts +76 -58
  121. package/dest/pxe.d.ts.map +1 -1
  122. package/dest/pxe.js +149 -138
  123. package/dest/storage/address_store/address_store.d.ts +1 -1
  124. package/dest/storage/address_store/address_store.d.ts.map +1 -1
  125. package/dest/storage/address_store/address_store.js +12 -11
  126. package/dest/storage/anchor_block_store/anchor_block_store.d.ts +9 -1
  127. package/dest/storage/anchor_block_store/anchor_block_store.d.ts.map +1 -1
  128. package/dest/storage/anchor_block_store/anchor_block_store.js +8 -1
  129. package/dest/storage/capsule_store/capsule_store.d.ts +24 -9
  130. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  131. package/dest/storage/capsule_store/capsule_store.js +130 -23
  132. package/dest/storage/contract_store/contract_store.d.ts +42 -16
  133. package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
  134. package/dest/storage/contract_store/contract_store.js +157 -84
  135. package/dest/storage/metadata.d.ts +1 -1
  136. package/dest/storage/metadata.js +1 -1
  137. package/dest/storage/note_store/note_store.d.ts +50 -51
  138. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  139. package/dest/storage/note_store/note_store.js +284 -263
  140. package/dest/storage/note_store/stored_note.d.ts +16 -0
  141. package/dest/storage/note_store/stored_note.d.ts.map +1 -0
  142. package/dest/storage/note_store/stored_note.js +43 -0
  143. package/dest/storage/private_event_store/private_event_store.d.ts +47 -7
  144. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  145. package/dest/storage/private_event_store/private_event_store.js +231 -73
  146. package/dest/storage/private_event_store/stored_private_event.d.ts +23 -0
  147. package/dest/storage/private_event_store/stored_private_event.d.ts.map +1 -0
  148. package/dest/storage/private_event_store/stored_private_event.js +56 -0
  149. package/dest/storage/tagging_store/recipient_tagging_store.d.ts +15 -8
  150. package/dest/storage/tagging_store/recipient_tagging_store.d.ts.map +1 -1
  151. package/dest/storage/tagging_store/recipient_tagging_store.js +88 -19
  152. package/dest/storage/tagging_store/sender_address_book_store.d.ts +1 -1
  153. package/dest/storage/tagging_store/sender_address_book_store.d.ts.map +1 -1
  154. package/dest/storage/tagging_store/sender_address_book_store.js +20 -14
  155. package/dest/storage/tagging_store/sender_tagging_store.d.ts +19 -9
  156. package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
  157. package/dest/storage/tagging_store/sender_tagging_store.js +253 -101
  158. package/dest/tagging/constants.d.ts +2 -0
  159. package/dest/tagging/constants.d.ts.map +1 -0
  160. package/dest/tagging/constants.js +10 -0
  161. package/dest/tagging/get_all_logs_by_tags.d.ts +24 -0
  162. package/dest/tagging/get_all_logs_by_tags.d.ts.map +1 -0
  163. package/dest/tagging/get_all_logs_by_tags.js +60 -0
  164. package/dest/tagging/index.d.ts +3 -2
  165. package/dest/tagging/index.d.ts.map +1 -1
  166. package/dest/tagging/index.js +2 -10
  167. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +3 -2
  168. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  169. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +12 -12
  170. package/dest/tagging/recipient_sync/utils/find_highest_indexes.js +2 -2
  171. package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts +3 -2
  172. package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts.map +1 -1
  173. package/dest/tagging/recipient_sync/utils/load_logs_for_range.js +5 -2
  174. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts +3 -2
  175. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts.map +1 -1
  176. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +8 -8
  177. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts +1 -1
  178. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts.map +1 -1
  179. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.js +5 -8
  180. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +5 -2
  181. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
  182. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +10 -5
  183. package/package.json +27 -18
  184. package/src/access_scopes.ts +9 -0
  185. package/src/bin/check_oracle_version.ts +1 -0
  186. package/src/block_synchronizer/block_synchronizer.ts +93 -32
  187. package/src/config/index.ts +14 -0
  188. package/src/config/package_info.ts +1 -1
  189. package/src/contract_function_simulator/benchmarked_node.ts +103 -0
  190. package/src/contract_function_simulator/contract_function_simulator.ts +350 -143
  191. package/src/contract_function_simulator/execution_note_cache.ts +44 -25
  192. package/src/contract_function_simulator/index.ts +1 -1
  193. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +6 -2
  194. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +2 -2
  195. package/src/contract_function_simulator/noir-structs/utility_context.ts +6 -25
  196. package/src/contract_function_simulator/oracle/interfaces.ts +22 -12
  197. package/src/contract_function_simulator/oracle/note_packing_utils.ts +10 -10
  198. package/src/contract_function_simulator/oracle/oracle.ts +79 -47
  199. package/src/contract_function_simulator/oracle/private_execution.ts +1 -69
  200. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +119 -137
  201. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +198 -115
  202. package/src/contract_logging.ts +39 -0
  203. package/src/contract_sync/contract_sync_service.ts +152 -0
  204. package/src/contract_sync/helpers.ts +98 -0
  205. package/src/debug/pxe_debug_utils.ts +63 -18
  206. package/src/entrypoints/client/bundle/index.ts +3 -0
  207. package/src/entrypoints/client/bundle/utils.ts +23 -16
  208. package/src/entrypoints/client/lazy/index.ts +3 -0
  209. package/src/entrypoints/client/lazy/utils.ts +24 -17
  210. package/src/entrypoints/pxe_creation_options.ts +4 -2
  211. package/src/entrypoints/server/index.ts +4 -0
  212. package/src/entrypoints/server/utils.ts +33 -41
  213. package/src/events/event_service.ts +19 -25
  214. package/src/events/private_event_filter_validator.ts +3 -5
  215. package/src/job_coordinator/job_coordinator.ts +150 -0
  216. package/src/logs/log_service.ts +40 -34
  217. package/src/notes/note_service.ts +41 -45
  218. package/src/notes_filter.ts +26 -0
  219. package/src/oracle_version.ts +4 -3
  220. package/src/private_kernel/hints/{compute_tx_include_by_timestamp.ts → compute_tx_expiration_timestamp.ts} +13 -13
  221. package/src/private_kernel/hints/index.ts +2 -2
  222. package/src/private_kernel/hints/{build_private_kernel_reset_private_inputs.ts → private_kernel_reset_private_inputs_builder.ts} +39 -28
  223. package/src/private_kernel/private_kernel_execution_prover.ts +15 -14
  224. package/src/private_kernel/private_kernel_oracle.ts +116 -36
  225. package/src/pxe.ts +280 -209
  226. package/src/storage/address_store/address_store.ts +15 -15
  227. package/src/storage/anchor_block_store/anchor_block_store.ts +8 -0
  228. package/src/storage/capsule_store/capsule_store.ts +159 -23
  229. package/src/storage/contract_store/contract_store.ts +186 -96
  230. package/src/storage/metadata.ts +1 -1
  231. package/src/storage/note_store/note_store.ts +326 -320
  232. package/src/storage/note_store/stored_note.ts +48 -0
  233. package/src/storage/private_event_store/private_event_store.ts +301 -79
  234. package/src/storage/private_event_store/stored_private_event.ts +73 -0
  235. package/src/storage/tagging_store/recipient_tagging_store.ts +106 -20
  236. package/src/storage/tagging_store/sender_address_book_store.ts +20 -14
  237. package/src/storage/tagging_store/sender_tagging_store.ts +294 -109
  238. package/src/tagging/constants.ts +10 -0
  239. package/src/tagging/get_all_logs_by_tags.ts +92 -0
  240. package/src/tagging/index.ts +2 -11
  241. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +25 -11
  242. package/src/tagging/recipient_sync/utils/find_highest_indexes.ts +2 -2
  243. package/src/tagging/recipient_sync/utils/load_logs_for_range.ts +7 -1
  244. package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +10 -7
  245. package/src/tagging/sender_sync/utils/get_status_change_of_pending.ts +5 -13
  246. package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +16 -4
  247. package/dest/contract_function_simulator/proxied_node.d.ts +0 -9
  248. package/dest/contract_function_simulator/proxied_node.d.ts.map +0 -1
  249. package/dest/contract_function_simulator/proxied_node.js +0 -27
  250. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts +0 -28
  251. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts.map +0 -1
  252. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts +0 -4
  253. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts.map +0 -1
  254. package/dest/private_kernel/private_kernel_oracle_impl.d.ts +0 -46
  255. package/dest/private_kernel/private_kernel_oracle_impl.d.ts.map +0 -1
  256. package/dest/private_kernel/private_kernel_oracle_impl.js +0 -86
  257. package/dest/public_storage/public_storage_service.d.ts +0 -24
  258. package/dest/public_storage/public_storage_service.d.ts.map +0 -1
  259. package/dest/public_storage/public_storage_service.js +0 -26
  260. package/dest/tree_membership/tree_membership_service.d.ts +0 -52
  261. package/dest/tree_membership/tree_membership_service.d.ts.map +0 -1
  262. package/dest/tree_membership/tree_membership_service.js +0 -84
  263. package/src/contract_function_simulator/proxied_node.ts +0 -33
  264. package/src/private_kernel/private_kernel_oracle_impl.ts +0 -133
  265. package/src/public_storage/public_storage_service.ts +0 -33
  266. package/src/tree_membership/tree_membership_service.ts +0 -112
@@ -1,16 +1,18 @@
1
- import { toArray } from '@aztec/foundation/iterable';
2
1
  import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
2
  import type { DirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';
4
3
  import { TxHash } from '@aztec/stdlib/tx';
5
4
 
6
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../../tagging/index.js';
5
+ import type { StagedStore } from '../../job_coordinator/job_coordinator.js';
6
+ import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../../tagging/constants.js';
7
7
 
8
8
  /**
9
9
  * Data provider of tagging data used when syncing the sender tagging indexes. The recipient counterpart of this class
10
- * is called RecipientTaggingStore. We have the providers separate for the sender and recipient because
10
+ * is called RecipientTaggingStore. We have the data stores separate for sender and recipient because
11
11
  * the algorithms are completely disjoint and there is not data reuse between the two.
12
12
  */
13
- export class SenderTaggingStore {
13
+ export class SenderTaggingStore implements StagedStore {
14
+ readonly storeName = 'sender_tagging';
15
+
14
16
  #store: AztecAsyncKVStore;
15
17
 
16
18
  // Stores the pending indexes for each directional app tagging secret. Pending here means that the tx that contained
@@ -21,18 +23,106 @@ export class SenderTaggingStore {
21
23
  // the smaller ones are irrelevant due to tx atomicity.
22
24
  //
23
25
  // TODO(#17615): This assumes no logs are used in the non-revertible phase.
26
+ //
27
+ // directional app tagging secret => { pending index, txHash }[]
24
28
  #pendingIndexes: AztecAsyncMap<string, { index: number; txHash: string }[]>;
25
29
 
30
+ // jobId => directional app tagging secret => { pending index, txHash }[]
31
+ #pendingIndexesForJob: Map<string, Map<string, { index: number; txHash: string }[]>>;
32
+
26
33
  // Stores the last (highest) finalized index for each directional app tagging secret. We care only about the last
27
34
  // index because unlike the pending indexes, it will never happen that a finalized index would be removed and hence
28
35
  // we don't need to store the history.
36
+ //
37
+ // directional app tagging secret => highest finalized index
29
38
  #lastFinalizedIndexes: AztecAsyncMap<string, number>;
30
39
 
40
+ // jobId => directional app tagging secret => highest finalized index
41
+ #lastFinalizedIndexesForJob: Map<string, Map<string, number>>;
42
+
31
43
  constructor(store: AztecAsyncKVStore) {
32
44
  this.#store = store;
33
45
 
34
46
  this.#pendingIndexes = this.#store.openMap('pending_indexes');
35
47
  this.#lastFinalizedIndexes = this.#store.openMap('last_finalized_indexes');
48
+
49
+ this.#pendingIndexesForJob = new Map();
50
+ this.#lastFinalizedIndexesForJob = new Map();
51
+ }
52
+
53
+ #getPendingIndexesForJob(jobId: string): Map<string, { index: number; txHash: string }[]> {
54
+ let pendingIndexesForJob = this.#pendingIndexesForJob.get(jobId);
55
+ if (!pendingIndexesForJob) {
56
+ pendingIndexesForJob = new Map();
57
+ this.#pendingIndexesForJob.set(jobId, pendingIndexesForJob);
58
+ }
59
+ return pendingIndexesForJob;
60
+ }
61
+
62
+ #getLastFinalizedIndexesForJob(jobId: string): Map<string, number> {
63
+ let jobStagedLastFinalizedIndexes = this.#lastFinalizedIndexesForJob.get(jobId);
64
+ if (!jobStagedLastFinalizedIndexes) {
65
+ jobStagedLastFinalizedIndexes = new Map();
66
+ this.#lastFinalizedIndexesForJob.set(jobId, jobStagedLastFinalizedIndexes);
67
+ }
68
+ return jobStagedLastFinalizedIndexes;
69
+ }
70
+
71
+ async #readPendingIndexes(jobId: string, secret: string): Promise<{ index: number; txHash: string }[]> {
72
+ // Always issue DB read to keep IndexedDB transaction alive (they auto-commit when a new micro-task starts and there
73
+ // are no pending read requests). The staged value still takes precedence if it exists.
74
+ const dbValue = await this.#pendingIndexes.getAsync(secret);
75
+ const staged = this.#getPendingIndexesForJob(jobId).get(secret);
76
+ return staged !== undefined ? staged : (dbValue ?? []);
77
+ }
78
+
79
+ #writePendingIndexes(jobId: string, secret: string, pendingIndexes: { index: number; txHash: string }[]) {
80
+ this.#getPendingIndexesForJob(jobId).set(secret, pendingIndexes);
81
+ }
82
+
83
+ async #readLastFinalizedIndex(jobId: string, secret: string): Promise<number | undefined> {
84
+ // Always issue DB read to keep IndexedDB transaction alive (they auto-commit when a new micro-task starts and there
85
+ // are no pending read requests). The staged value still takes precedence if it exists.
86
+ const dbValue = await this.#lastFinalizedIndexes.getAsync(secret);
87
+ const staged = this.#getLastFinalizedIndexesForJob(jobId).get(secret);
88
+ return staged ?? dbValue;
89
+ }
90
+
91
+ #writeLastFinalizedIndex(jobId: string, secret: string, lastFinalizedIndex: number) {
92
+ this.#getLastFinalizedIndexesForJob(jobId).set(secret, lastFinalizedIndex);
93
+ }
94
+
95
+ /**
96
+ * Writes all job-specific in-memory data to persistent storage.
97
+ *
98
+ * @remark This method must run in a DB transaction context. It's designed to be called from JobCoordinator#commitJob.
99
+ */
100
+ async commit(jobId: string): Promise<void> {
101
+ const pendingIndexesForJob = this.#pendingIndexesForJob.get(jobId);
102
+ if (pendingIndexesForJob) {
103
+ for (const [secret, pendingIndexes] of pendingIndexesForJob.entries()) {
104
+ if (pendingIndexes.length === 0) {
105
+ await this.#pendingIndexes.delete(secret);
106
+ } else {
107
+ await this.#pendingIndexes.set(secret, pendingIndexes);
108
+ }
109
+ }
110
+ }
111
+
112
+ const lastFinalizedIndexesForJob = this.#lastFinalizedIndexesForJob.get(jobId);
113
+ if (lastFinalizedIndexesForJob) {
114
+ for (const [secret, lastFinalizedIndex] of lastFinalizedIndexesForJob.entries()) {
115
+ await this.#lastFinalizedIndexes.set(secret, lastFinalizedIndex);
116
+ }
117
+ }
118
+
119
+ return this.discardStaged(jobId);
120
+ }
121
+
122
+ discardStaged(jobId: string): Promise<void> {
123
+ this.#pendingIndexesForJob.delete(jobId);
124
+ this.#lastFinalizedIndexesForJob.delete(jobId);
125
+ return Promise.resolve();
36
126
  }
37
127
 
38
128
  /**
@@ -43,6 +133,7 @@ export class SenderTaggingStore {
43
133
  * @param preTags - The pre-tags containing the directional app tagging secrets and the indexes that are to be
44
134
  * stored in the db.
45
135
  * @param txHash - The tx in which the pretags were used in private logs.
136
+ * @param jobId - job context for staged writes to this store. See `JobCoordinator` for more details.
46
137
  * @throws If any two pre-tags contain the same directional app tagging secret. This is enforced because we care
47
138
  * only about the highest index for a given secret that was used in the tx. Hence this check is a good way to catch
48
139
  * bugs.
@@ -56,55 +147,80 @@ export class SenderTaggingStore {
56
147
  * This is enforced because this should never happen if the syncing is done correctly as we look for logs from higher
57
148
  * indexes than finalized ones.
58
149
  */
59
- async storePendingIndexes(preTags: PreTag[], txHash: TxHash) {
150
+ storePendingIndexes(preTags: PreTag[], txHash: TxHash, jobId: string): Promise<void> {
151
+ if (preTags.length === 0) {
152
+ return Promise.resolve();
153
+ }
154
+
60
155
  // The secrets in pre-tags should be unique because we always store just the highest index per given secret-txHash
61
156
  // pair. Below we check that this is the case.
62
157
  const secretsSet = new Set(preTags.map(preTag => preTag.secret.toString()));
63
158
  if (secretsSet.size !== preTags.length) {
64
- throw new Error(`Duplicate secrets found when storing pending indexes`);
159
+ return Promise.reject(new Error(`Duplicate secrets found when storing pending indexes`));
65
160
  }
66
161
 
67
- for (const { secret, index } of preTags) {
68
- // First we check that for any secret the highest used index in tx is not further than window length from
69
- // the highest finalized index.
70
- const finalizedIndex = (await this.getLastFinalizedIndex(secret)) ?? 0;
71
- if (index > finalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN) {
72
- throw new Error(
73
- `Highest used index ${index} is further than window length from the highest finalized index ${finalizedIndex}.
74
- Tagging window length ${UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN} is configured too low. Contact the Aztec team
75
- to increase it!`,
76
- );
77
- }
162
+ const txHashStr = txHash.toString();
78
163
 
79
- // Throw if the new pending index is lower than or equal to the last finalized index
80
- const secretStr = secret.toString();
81
- const lastFinalizedIndex = await this.#lastFinalizedIndexes.getAsync(secretStr);
82
- if (lastFinalizedIndex !== undefined && index <= lastFinalizedIndex) {
83
- throw new Error(
84
- `Cannot store pending index ${index} for secret ${secretStr}: ` +
85
- `it is lower than or equal to the last finalized index ${lastFinalizedIndex}`,
86
- );
87
- }
164
+ return this.#store.transactionAsync(async () => {
165
+ // Prefetch all data, start reads during iteration to keep IndexedDB transaction alive
166
+ const preTagReadPromises = preTags.map(({ secret, index }) => {
167
+ const secretStr = secret.toString();
168
+ return {
169
+ secret,
170
+ secretStr,
171
+ index,
172
+ pending: this.#readPendingIndexes(jobId, secretStr),
173
+ finalized: this.#readLastFinalizedIndex(jobId, secretStr),
174
+ };
175
+ });
88
176
 
89
- // Check if this secret + txHash combination already exists
90
- const txHashStr = txHash.toString();
91
- const existingForSecret = (await this.#pendingIndexes.getAsync(secretStr)) ?? [];
92
- const existingForSecretAndTx = existingForSecret.find(entry => entry.txHash === txHashStr);
177
+ // Await all reads together
178
+ const preTagData = await Promise.all(
179
+ preTagReadPromises.map(async item => ({
180
+ ...item,
181
+ pendingData: await item.pending,
182
+ finalizedIndex: await item.finalized,
183
+ })),
184
+ );
93
185
 
94
- if (existingForSecretAndTx) {
95
- // If it exists with a different index, throw an error
96
- if (existingForSecretAndTx.index !== index) {
186
+ // Process in memory and validate
187
+ for (const { secretStr, index, pendingData, finalizedIndex } of preTagData) {
188
+ // First we check that for any secret the highest used index in tx is not further than window length from
189
+ // the highest finalized index.
190
+ if (index > (finalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN) {
97
191
  throw new Error(
98
- `Cannot store index ${index} for secret ${secretStr} and txHash ${txHashStr}: ` +
99
- `a different index ${existingForSecretAndTx.index} already exists for this secret-txHash pair`,
192
+ `Highest used index ${index} is further than window length from the highest finalized index ${finalizedIndex ?? 0}.
193
+ Tagging window length ${UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN} is configured too low. Contact the Aztec team
194
+ to increase it!`,
100
195
  );
101
196
  }
102
- // If it exists with the same index, ignore the update (no-op)
103
- } else {
104
- // If it doesn't exist, add it
105
- await this.#pendingIndexes.set(secretStr, [...existingForSecret, { index, txHash: txHashStr }]);
197
+
198
+ // Throw if the new pending index is lower than or equal to the last finalized index
199
+ if (finalizedIndex !== undefined && index <= finalizedIndex) {
200
+ throw new Error(
201
+ `Cannot store pending index ${index} for secret ${secretStr}: ` +
202
+ `it is lower than or equal to the last finalized index ${finalizedIndex}`,
203
+ );
204
+ }
205
+
206
+ // Check if this secret + txHash combination already exists
207
+ const existingForSecretAndTx = pendingData.find(entry => entry.txHash === txHashStr);
208
+
209
+ if (existingForSecretAndTx) {
210
+ // If it exists with a different index, throw an error
211
+ if (existingForSecretAndTx.index !== index) {
212
+ throw new Error(
213
+ `Cannot store index ${index} for secret ${secretStr} and txHash ${txHashStr}: ` +
214
+ `a different index ${existingForSecretAndTx.index} already exists for this secret-txHash pair`,
215
+ );
216
+ }
217
+ // If it exists with the same index, ignore the update (no-op)
218
+ } else {
219
+ // If it doesn't exist, add it
220
+ this.#writePendingIndexes(jobId, secretStr, [...pendingData, { index, txHash: txHashStr }]);
221
+ }
106
222
  }
107
- }
223
+ });
108
224
  }
109
225
 
110
226
  /**
@@ -116,16 +232,19 @@ export class SenderTaggingStore {
116
232
  * @returns An array of unique transaction hashes for pending transactions that contain indexes in the range
117
233
  * [startIndex, endIndex). Returns an empty array if no pending indexes exist in the range.
118
234
  */
119
- async getTxHashesOfPendingIndexes(
235
+ getTxHashesOfPendingIndexes(
120
236
  secret: DirectionalAppTaggingSecret,
121
237
  startIndex: number,
122
238
  endIndex: number,
239
+ jobId: string,
123
240
  ): Promise<TxHash[]> {
124
- const existing = (await this.#pendingIndexes.getAsync(secret.toString())) ?? [];
125
- const txHashes = existing
126
- .filter(entry => entry.index >= startIndex && entry.index < endIndex)
127
- .map(entry => entry.txHash);
128
- return Array.from(new Set(txHashes)).map(TxHash.fromString);
241
+ return this.#store.transactionAsync(async () => {
242
+ const existing = await this.#readPendingIndexes(jobId, secret.toString());
243
+ const txHashes = existing
244
+ .filter(entry => entry.index >= startIndex && entry.index < endIndex)
245
+ .map(entry => entry.txHash);
246
+ return Array.from(new Set(txHashes)).map(TxHash.fromString);
247
+ });
129
248
  }
130
249
 
131
250
  /**
@@ -133,8 +252,8 @@ export class SenderTaggingStore {
133
252
  * @param secret - The secret to get the last finalized index for.
134
253
  * @returns The last (highest) finalized index for the given secret.
135
254
  */
136
- getLastFinalizedIndex(secret: DirectionalAppTaggingSecret): Promise<number | undefined> {
137
- return this.#lastFinalizedIndexes.getAsync(secret.toString());
255
+ getLastFinalizedIndex(secret: DirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
256
+ return this.#store.transactionAsync(() => this.#readLastFinalizedIndex(jobId, secret.toString()));
138
257
  }
139
258
 
140
259
  /**
@@ -143,102 +262,168 @@ export class SenderTaggingStore {
143
262
  * @param secret - The directional app tagging secret to query the last used index for.
144
263
  * @returns The last used index.
145
264
  */
146
- async getLastUsedIndex(secret: DirectionalAppTaggingSecret): Promise<number | undefined> {
265
+ getLastUsedIndex(secret: DirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
147
266
  const secretStr = secret.toString();
148
- const pendingTxScopedIndexes = (await this.#pendingIndexes.getAsync(secretStr)) ?? [];
149
- const pendingIndexes = pendingTxScopedIndexes.map(entry => entry.index);
150
267
 
151
- if (pendingTxScopedIndexes.length === 0) {
152
- return this.#lastFinalizedIndexes.getAsync(secretStr);
153
- }
268
+ return this.#store.transactionAsync(async () => {
269
+ const pendingPromise = this.#readPendingIndexes(jobId, secretStr);
270
+ const finalizedPromise = this.#readLastFinalizedIndex(jobId, secretStr);
271
+
272
+ const [pendingTxScopedIndexes, lastFinalized] = await Promise.all([pendingPromise, finalizedPromise]);
273
+ const pendingIndexes = pendingTxScopedIndexes.map(entry => entry.index);
154
274
 
155
- // As the last used index we return the highest one from the pending indexes. Note that this value will be always
156
- // higher than the last finalized index because we prune lower pending indexes when a tx is finalized.
157
- return Math.max(...pendingIndexes);
275
+ if (pendingTxScopedIndexes.length === 0) {
276
+ return lastFinalized;
277
+ }
278
+
279
+ // As the last used index we return the highest one from the pending indexes. Note that this value will be always
280
+ // higher than the last finalized index because we prune lower pending indexes when a tx is finalized.
281
+ return Math.max(...pendingIndexes);
282
+ });
158
283
  }
159
284
 
160
285
  /**
161
286
  * Drops all pending indexes corresponding to the given transaction hashes.
162
287
  */
163
- async dropPendingIndexes(txHashes: TxHash[]) {
288
+ dropPendingIndexes(txHashes: TxHash[], jobId: string): Promise<void> {
164
289
  if (txHashes.length === 0) {
165
- return;
290
+ return Promise.resolve();
166
291
  }
167
292
 
168
- const txHashStrs = new Set<string>(txHashes.map(txHash => txHash.toString()));
169
- const allSecrets = await toArray(this.#pendingIndexes.keysAsync());
293
+ const txHashStrings = new Set<string>(txHashes.map(txHash => txHash.toString()));
170
294
 
171
- for (const secret of allSecrets) {
172
- const pendingData = await this.#pendingIndexes.getAsync(secret);
173
- if (pendingData) {
174
- const filtered = pendingData.filter(item => !txHashStrs.has(item.txHash));
175
- if (filtered.length === 0) {
176
- await this.#pendingIndexes.delete(secret);
177
- } else if (filtered.length !== pendingData.length) {
178
- // Some items were filtered out, so update the pending data
179
- await this.#pendingIndexes.set(secret, filtered);
295
+ return this.#store.transactionAsync(async () => {
296
+ // Prefetch all data, start reads during iteration to keep IndexedDB transaction alive
297
+ const secretReadPromises: Map<string, Promise<{ index: number; txHash: string }[]>> = new Map();
298
+
299
+ for await (const secret of this.#pendingIndexes.keysAsync()) {
300
+ secretReadPromises.set(secret, this.#readPendingIndexes(jobId, secret));
301
+ }
302
+
303
+ // Add staged-only secrets (sync, no DB)
304
+ for (const secret of this.#getPendingIndexesForJob(jobId).keys()) {
305
+ if (!secretReadPromises.has(secret)) {
306
+ secretReadPromises.set(secret, Promise.resolve(this.#getPendingIndexesForJob(jobId).get(secret) ?? []));
180
307
  }
181
- // else: No items were filtered out (txHashes not found for this secret) --> no-op
182
308
  }
183
- }
309
+
310
+ // Await all reads together
311
+ const secrets = [...secretReadPromises.keys()];
312
+ const pendingDataResults = await Promise.all(secretReadPromises.values());
313
+
314
+ // Process in memory
315
+ for (let i = 0; i < secrets.length; i++) {
316
+ const secret = secrets[i];
317
+ const pendingData = pendingDataResults[i];
318
+
319
+ if (pendingData && pendingData.length > 0) {
320
+ const filtered = pendingData.filter(item => !txHashStrings.has(item.txHash));
321
+ if (filtered.length === 0) {
322
+ this.#writePendingIndexes(jobId, secret, []);
323
+ } else if (filtered.length !== pendingData.length) {
324
+ // Some items were filtered out, so update the pending data
325
+ this.#writePendingIndexes(jobId, secret, filtered);
326
+ }
327
+ // else: No items were filtered out (txHashes not found for this secret) --> no-op
328
+ }
329
+ }
330
+ });
184
331
  }
185
332
 
186
333
  /**
187
334
  * Updates pending indexes corresponding to the given transaction hashes to be finalized and prunes any lower pending
188
335
  * indexes.
189
336
  */
190
- async finalizePendingIndexes(txHashes: TxHash[]) {
337
+ finalizePendingIndexes(txHashes: TxHash[], jobId: string): Promise<void> {
191
338
  if (txHashes.length === 0) {
192
- return;
339
+ return Promise.resolve();
193
340
  }
194
341
 
195
- for (const txHash of txHashes) {
196
- const txHashStr = txHash.toString();
342
+ const txHashStrings = new Set(txHashes.map(tx => tx.toString()));
197
343
 
198
- const allSecrets = await toArray(this.#pendingIndexes.keysAsync());
344
+ return this.#store.transactionAsync(async () => {
345
+ // Prefetch all data, start reads during iteration to keep IndexedDB transaction alive
346
+ const secretDataPromises: Map<
347
+ string,
348
+ { pending: Promise<{ index: number; txHash: string }[]>; finalized: Promise<number | undefined> }
349
+ > = new Map();
199
350
 
200
- for (const secret of allSecrets) {
201
- const pendingData = await this.#pendingIndexes.getAsync(secret);
202
- if (!pendingData) {
203
- continue;
351
+ for await (const secret of this.#pendingIndexes.keysAsync()) {
352
+ secretDataPromises.set(secret, {
353
+ pending: this.#readPendingIndexes(jobId, secret),
354
+ finalized: this.#readLastFinalizedIndex(jobId, secret),
355
+ });
356
+ }
357
+
358
+ // Add staged-only secrets (sync, no DB)
359
+ for (const secret of this.#getPendingIndexesForJob(jobId).keys()) {
360
+ if (!secretDataPromises.has(secret)) {
361
+ secretDataPromises.set(secret, {
362
+ pending: Promise.resolve(this.#getPendingIndexesForJob(jobId).get(secret) ?? []),
363
+ finalized: Promise.resolve(this.#getLastFinalizedIndexesForJob(jobId).get(secret)),
364
+ });
204
365
  }
366
+ }
367
+
368
+ // Await all reads together
369
+ const secrets = [...secretDataPromises.keys()];
370
+ const dataResults = await Promise.all(
371
+ secrets.map(async secret => ({
372
+ secret,
373
+ pendingData: await secretDataPromises.get(secret)!.pending,
374
+ lastFinalized: await secretDataPromises.get(secret)!.finalized,
375
+ })),
376
+ );
205
377
 
206
- const matchingIndexes = pendingData.filter(item => item.txHash === txHashStr).map(item => item.index);
207
- if (matchingIndexes.length === 0) {
378
+ // Process all txHashes for each secret in memory
379
+ for (const { secret, pendingData, lastFinalized } of dataResults) {
380
+ if (!pendingData || pendingData.length === 0) {
208
381
  continue;
209
382
  }
210
383
 
211
- if (matchingIndexes.length > 1) {
212
- // We should always just store the highest pending index for a given tx hash and secret because the lower
213
- // values are irrelevant.
214
- throw new Error(`Multiple pending indexes found for tx hash ${txHashStr} and secret ${secret}`);
215
- }
384
+ let currentPending = pendingData;
385
+ let currentFinalized = lastFinalized;
216
386
 
217
- let lastFinalized = await this.#lastFinalizedIndexes.getAsync(secret);
218
- const newFinalized = matchingIndexes[0];
387
+ // Process all txHashes for this secret
388
+ for (const txHashStr of txHashStrings) {
389
+ const matchingIndexes = currentPending.filter(item => item.txHash === txHashStr).map(item => item.index);
390
+ if (matchingIndexes.length === 0) {
391
+ continue;
392
+ }
219
393
 
220
- if (newFinalized < (lastFinalized ?? 0)) {
221
- // This should never happen because when last finalized index was finalized we should have pruned the lower
222
- // pending indexes.
223
- throw new Error(
224
- `New finalized index ${newFinalized} is smaller than the current last finalized index ${lastFinalized}`,
225
- );
226
- }
394
+ if (matchingIndexes.length > 1) {
395
+ // We should always just store the highest pending index for a given tx hash and secret because the lower
396
+ // values are irrelevant.
397
+ throw new Error(`Multiple pending indexes found for tx hash ${txHashStr} and secret ${secret}`);
398
+ }
227
399
 
228
- await this.#lastFinalizedIndexes.set(secret, newFinalized);
229
- lastFinalized = newFinalized;
400
+ const newFinalized = matchingIndexes[0];
230
401
 
231
- // When we add pending indexes, we ensure they are higher than the last finalized index. However, because we
232
- // cannot control the order in which transactions are finalized, there may be pending indexes that are now
233
- // obsolete because they are lower than the most recently finalized index. For this reason, we prune these
234
- // outdated pending indexes.
235
- const remainingItemsOfHigherIndex = pendingData.filter(item => item.index > (lastFinalized ?? 0));
236
- if (remainingItemsOfHigherIndex.length === 0) {
237
- await this.#pendingIndexes.delete(secret);
238
- } else {
239
- await this.#pendingIndexes.set(secret, remainingItemsOfHigherIndex);
402
+ if (newFinalized < (currentFinalized ?? 0)) {
403
+ // This should never happen because when last finalized index was finalized we should have pruned the lower
404
+ // pending indexes.
405
+ throw new Error(
406
+ `New finalized index ${newFinalized} is smaller than the current last finalized index ${currentFinalized}`,
407
+ );
408
+ }
409
+
410
+ currentFinalized = newFinalized;
411
+
412
+ // When we add pending indexes, we ensure they are higher than the last finalized index. However, because we
413
+ // cannot control the order in which transactions are finalized, there may be pending indexes that are now
414
+ // obsolete because they are lower than the most recently finalized index. For this reason, we prune these
415
+ // outdated pending indexes.
416
+ currentPending = currentPending.filter(item => item.index > currentFinalized!);
417
+ }
418
+
419
+ // Write final state if changed
420
+ if (currentFinalized !== lastFinalized) {
421
+ this.#writeLastFinalizedIndex(jobId, secret, currentFinalized!);
422
+ }
423
+ if (currentPending !== pendingData) {
424
+ this.#writePendingIndexes(jobId, secret, currentPending);
240
425
  }
241
426
  }
242
- }
427
+ });
243
428
  }
244
429
  }
@@ -0,0 +1,10 @@
1
+ // This window has to be as large as the largest expected number of logs emitted in a tx for a given directional app
2
+ // tagging secret. If we get more tag indexes consumed than this window, an error is thrown in `PXE::proveTx` function.
3
+ // This is set to a larger value than MAX_PRIVATE_LOGS_PER_TX (currently 64) because there could be more than
4
+ // MAX_PRIVATE_LOGS_PER_TX indexes consumed in case the logs are squashed. This happens when the log contains a note
5
+ // and the note is nullified in the same tx.
6
+ //
7
+ // Having a large window significantly slowed down `e2e_l1_with_wall_time` test as there we perform sync for more than
8
+ // 1000 secrets. For this reason we set it to a relatively low value of 20. 20 should be sufficient for all the use
9
+ // cases.
10
+ export const UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN = 20;
@@ -0,0 +1,92 @@
1
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
2
+ import type { BlockHash } from '@aztec/stdlib/block';
3
+ import { MAX_LOGS_PER_TAG, MAX_RPC_LEN } from '@aztec/stdlib/interfaces/api-limit';
4
+ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
+ import type { SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
6
+
7
+ /**
8
+ * Generic pagination helper that fetches all pages of results.
9
+ * @param numTags - The number of tags being queried (determines result array size).
10
+ * @param fetchPage - Function that fetches a single page of results given a page number.
11
+ * @returns An array of arrays, one per tag, containing all results across all pages.
12
+ */
13
+ async function getAllPages<T>(numTags: number, fetchPage: (page: number) => Promise<T[][]>): Promise<T[][]> {
14
+ const allResultsPerTag: T[][] = Array.from({ length: numTags }, () => []);
15
+ let page = 0;
16
+ let hasMore = true;
17
+
18
+ while (hasMore) {
19
+ const resultsPage = await fetchPage(page);
20
+ hasMore = false;
21
+
22
+ for (let i = 0; i < resultsPage.length; i++) {
23
+ allResultsPerTag[i].push(...resultsPage[i]);
24
+ if (resultsPage[i].length === MAX_LOGS_PER_TAG) {
25
+ hasMore = true;
26
+ }
27
+ }
28
+ page++;
29
+ }
30
+
31
+ return allResultsPerTag;
32
+ }
33
+
34
+ /**
35
+ * Splits tags into chunks of MAX_RPC_LEN, fetches logs for each chunk using getAllPages, then stitches the results
36
+ * back into a single array preserving the original tag order.
37
+ */
38
+ async function getAllPagesInBatches<Tag, T>(
39
+ tags: Tag[],
40
+ fetchAllPagesForBatch: (batch: Tag[]) => Promise<T[][]>,
41
+ ): Promise<T[][]> {
42
+ if (tags.length <= MAX_RPC_LEN) {
43
+ return fetchAllPagesForBatch(tags);
44
+ }
45
+
46
+ const batches: Tag[][] = [];
47
+ for (let i = 0; i < tags.length; i += MAX_RPC_LEN) {
48
+ batches.push(tags.slice(i, i + MAX_RPC_LEN));
49
+ }
50
+ const batchResults = await Promise.all(batches.map(fetchAllPagesForBatch));
51
+ return batchResults.flat();
52
+ }
53
+
54
+ /**
55
+ * Fetches all private logs for the given tags, automatically paginating through all pages.
56
+ * @param aztecNode - The Aztec node to query.
57
+ * @param tags - The siloed tags to search for.
58
+ * @param anchorBlockHash - reference block for the Aztec node query, throws if block is not found there (typically
59
+ * because of reorgs).
60
+ * @returns An array of log arrays, one per tag, containing all logs across all pages.
61
+ */
62
+ export function getAllPrivateLogsByTags(
63
+ aztecNode: AztecNode,
64
+ tags: SiloedTag[],
65
+ anchorBlockHash: BlockHash,
66
+ ): Promise<TxScopedL2Log[][]> {
67
+ return getAllPagesInBatches(tags, batch =>
68
+ getAllPages(batch.length, page => aztecNode.getPrivateLogsByTags(batch, page, anchorBlockHash)),
69
+ );
70
+ }
71
+
72
+ /**
73
+ * Fetches all public logs for the given tags from a contract, automatically paginating through all pages.
74
+ * @param aztecNode - The Aztec node to query.
75
+ * @param contractAddress - The contract address to search logs for.
76
+ * @param tags - The tags to search for.
77
+ * @param anchorBlockHash - reference block for the Aztec node query, throws if block is not found there (typically
78
+ * because of reorgs).
79
+ * @returns An array of log arrays, one per tag, containing all logs across all pages.
80
+ */
81
+ export function getAllPublicLogsByTagsFromContract(
82
+ aztecNode: AztecNode,
83
+ contractAddress: AztecAddress,
84
+ tags: Tag[],
85
+ anchorBlockHash: BlockHash,
86
+ ): Promise<TxScopedL2Log[][]> {
87
+ return getAllPagesInBatches(tags, batch =>
88
+ getAllPages(batch.length, page =>
89
+ aztecNode.getPublicLogsByTagsFromContract(contractAddress, batch, page, anchorBlockHash),
90
+ ),
91
+ );
92
+ }
@@ -11,17 +11,8 @@
11
11
 
12
12
  export { loadPrivateLogsForSenderRecipientPair } from './recipient_sync/load_private_logs_for_sender_recipient_pair.js';
13
13
  export { syncSenderTaggingIndexes } from './sender_sync/sync_sender_tagging_indexes.js';
14
-
15
- // This window has to be as large as the largest expected number of logs emitted in a tx for a given directional app
16
- // tagging secret. If we get more tag indexes consumed than this window, an error is thrown in `PXE::proveTx` function.
17
- // This is set to a larger value than MAX_PRIVATE_LOGS_PER_TX (currently 64) because there could be more than
18
- // MAX_PRIVATE_LOGS_PER_TX indexes consumed in case the logs are squashed. This happens when the log contains a note
19
- // and the note is nullified in the same tx.
20
- //
21
- // Having a large window significantly slowed down `e2e_l1_with_wall_time` test as there we perform sync for more than
22
- // 1000 secrets. For this reason we set it to a relatively low value of 20. 20 should be sufficient for all the use
23
- // cases.
24
- export const UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN = 20;
14
+ export { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from './constants.js';
15
+ export { getAllPrivateLogsByTags, getAllPublicLogsByTagsFromContract } from './get_all_logs_by_tags.js';
25
16
 
26
17
  // Re-export tagging-related types from stdlib
27
18
  export { DirectionalAppTaggingSecret, Tag, SiloedTag } from '@aztec/stdlib/logs';