@aztec/pxe 0.0.1-commit.b8a057fa → 0.0.1-commit.be03c316

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 (167) hide show
  1. package/dest/bin/check_oracle_version.js +3 -8
  2. package/dest/bin/index.d.ts +2 -2
  3. package/dest/bin/index.d.ts.map +1 -1
  4. package/dest/bin/index.js +1 -1
  5. package/dest/bin/oracle_version_helpers.d.ts +8 -25
  6. package/dest/bin/oracle_version_helpers.d.ts.map +1 -1
  7. package/dest/bin/oracle_version_helpers.js +11 -219
  8. package/dest/contract/helpers.d.ts +1 -1
  9. package/dest/contract/helpers.d.ts.map +1 -1
  10. package/dest/contract/helpers.js +3 -3
  11. package/dest/contract/skip_sync_contracts.d.ts +11 -0
  12. package/dest/contract/skip_sync_contracts.d.ts.map +1 -0
  13. package/dest/contract/skip_sync_contracts.js +18 -0
  14. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts +39 -0
  15. package/dest/contract_function_simulator/aztec_node_read_cache.d.ts.map +1 -0
  16. package/dest/contract_function_simulator/aztec_node_read_cache.js +60 -0
  17. package/dest/contract_function_simulator/index.d.ts +3 -3
  18. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  19. package/dest/contract_function_simulator/index.js +1 -2
  20. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts +1 -1
  21. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts.map +1 -1
  22. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.js +7 -0
  23. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts +7 -9
  24. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts.map +1 -1
  25. package/dest/contract_function_simulator/noir-structs/resolved_tx.js +3 -44
  26. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts +5 -4
  27. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts.map +1 -1
  28. package/dest/contract_function_simulator/noir-structs/tx_effect_data.js +2 -2
  29. package/dest/contract_function_simulator/oracle/acir_callback.js +1 -1
  30. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts +3 -3
  31. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.d.ts.map +1 -1
  32. package/dest/contract_function_simulator/oracle/legacy_oracle_registry.js +34 -1
  33. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts +7 -4
  34. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
  35. package/dest/contract_function_simulator/oracle/oracle_registry.js +40 -13
  36. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts +87 -35
  37. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts.map +1 -1
  38. package/dest/contract_function_simulator/oracle/oracle_type_mappings.js +286 -286
  39. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -1
  40. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  41. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +7 -10
  42. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +14 -8
  43. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  44. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +61 -34
  45. package/dest/entrypoints/client/bundle/index.d.ts +2 -1
  46. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  47. package/dest/entrypoints/client/bundle/index.js +1 -0
  48. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  49. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  50. package/dest/entrypoints/client/bundle/utils.js +10 -4
  51. package/dest/entrypoints/client/lazy/index.d.ts +2 -1
  52. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  53. package/dest/entrypoints/client/lazy/index.js +1 -0
  54. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  55. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  56. package/dest/entrypoints/client/lazy/utils.js +10 -4
  57. package/dest/entrypoints/client/store.d.ts +14 -0
  58. package/dest/entrypoints/client/store.d.ts.map +1 -0
  59. package/dest/entrypoints/client/store.js +42 -0
  60. package/dest/entrypoints/server/index.d.ts +2 -1
  61. package/dest/entrypoints/server/index.d.ts.map +1 -1
  62. package/dest/entrypoints/server/index.js +1 -0
  63. package/dest/entrypoints/server/store.d.ts +18 -0
  64. package/dest/entrypoints/server/store.d.ts.map +1 -0
  65. package/dest/entrypoints/server/store.js +28 -0
  66. package/dest/entrypoints/server/utils.d.ts +1 -1
  67. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  68. package/dest/entrypoints/server/utils.js +8 -2
  69. package/dest/hooks/index.d.ts +2 -2
  70. package/dest/hooks/index.d.ts.map +1 -1
  71. package/dest/hooks/index.js +1 -0
  72. package/dest/hooks/resolve_tagging_secret_strategy.d.ts +3 -1
  73. package/dest/hooks/resolve_tagging_secret_strategy.d.ts.map +1 -1
  74. package/dest/hooks/resolve_tagging_secret_strategy.js +3 -3
  75. package/dest/logs/log_service.d.ts +3 -2
  76. package/dest/logs/log_service.d.ts.map +1 -1
  77. package/dest/logs/log_service.js +12 -3
  78. package/dest/messages/tx_resolver_service.d.ts +2 -2
  79. package/dest/messages/tx_resolver_service.d.ts.map +1 -1
  80. package/dest/messages/tx_resolver_service.js +7 -2
  81. package/dest/notes/note_service.d.ts +1 -1
  82. package/dest/notes/note_service.js +1 -1
  83. package/dest/oracle_version.d.ts +2 -2
  84. package/dest/oracle_version.js +3 -3
  85. package/dest/pxe.d.ts +1 -1
  86. package/dest/pxe.d.ts.map +1 -1
  87. package/dest/pxe.js +8 -5
  88. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts +1 -1
  89. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts.map +1 -1
  90. package/dest/storage/backwards_compatibility_tests/schema_tests.js +26 -2
  91. package/dest/storage/fact_store/index.d.ts +2 -2
  92. package/dest/storage/fact_store/index.d.ts.map +1 -1
  93. package/dest/storage/fact_store/index.js +1 -1
  94. package/dest/storage/fact_store/origin_state.d.ts +3 -1
  95. package/dest/storage/fact_store/origin_state.d.ts.map +1 -1
  96. package/dest/storage/fact_store/origin_state.js +7 -0
  97. package/dest/storage/metadata.d.ts +1 -1
  98. package/dest/storage/metadata.js +1 -1
  99. package/dest/storage/store_identity.d.ts +35 -0
  100. package/dest/storage/store_identity.d.ts.map +1 -0
  101. package/dest/storage/store_identity.js +44 -0
  102. package/dest/storage/tagging_store/sender_tagging_store.d.ts +19 -3
  103. package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
  104. package/dest/storage/tagging_store/sender_tagging_store.js +48 -11
  105. package/dest/tagging/constants.d.ts +3 -2
  106. package/dest/tagging/constants.d.ts.map +1 -1
  107. package/dest/tagging/constants.js +26 -5
  108. package/dest/tagging/index.d.ts +2 -2
  109. package/dest/tagging/index.d.ts.map +1 -1
  110. package/dest/tagging/index.js +1 -1
  111. package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts +9 -4
  112. package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts.map +1 -1
  113. package/dest/tagging/recipient_sync/sync_tagged_private_logs.js +60 -25
  114. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +1 -1
  115. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +1 -1
  116. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
  117. package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +6 -2
  118. package/dest/tagging/testing/tag_query_test_utils.d.ts +6 -0
  119. package/dest/tagging/testing/tag_query_test_utils.d.ts.map +1 -0
  120. package/dest/tagging/testing/tag_query_test_utils.js +10 -0
  121. package/package.json +17 -17
  122. package/src/bin/check_oracle_version.ts +3 -10
  123. package/src/bin/index.ts +1 -5
  124. package/src/bin/oracle_version_helpers.ts +11 -268
  125. package/src/contract/helpers.ts +3 -3
  126. package/src/contract/skip_sync_contracts.ts +23 -0
  127. package/src/contract_function_simulator/aztec_node_read_cache.ts +89 -0
  128. package/src/contract_function_simulator/index.ts +23 -3
  129. package/src/contract_function_simulator/noir-structs/resolved_tagging_strategy.ts +8 -0
  130. package/src/contract_function_simulator/noir-structs/resolved_tx.ts +11 -45
  131. package/src/contract_function_simulator/noir-structs/tx_effect_data.ts +4 -3
  132. package/src/contract_function_simulator/oracle/acir_callback.ts +1 -1
  133. package/src/contract_function_simulator/oracle/legacy_oracle_registry.ts +30 -3
  134. package/src/contract_function_simulator/oracle/oracle_registry.ts +32 -11
  135. package/src/contract_function_simulator/oracle/oracle_type_mappings.ts +285 -197
  136. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +17 -12
  137. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +92 -39
  138. package/src/entrypoints/client/bundle/index.ts +1 -0
  139. package/src/entrypoints/client/bundle/utils.ts +15 -3
  140. package/src/entrypoints/client/lazy/index.ts +1 -0
  141. package/src/entrypoints/client/lazy/utils.ts +15 -3
  142. package/src/entrypoints/client/store.ts +54 -0
  143. package/src/entrypoints/server/index.ts +1 -0
  144. package/src/entrypoints/server/store.ts +47 -0
  145. package/src/entrypoints/server/utils.ts +21 -7
  146. package/src/hooks/index.ts +1 -0
  147. package/src/hooks/resolve_tagging_secret_strategy.ts +3 -0
  148. package/src/logs/log_service.ts +11 -2
  149. package/src/messages/tx_resolver_service.ts +8 -8
  150. package/src/notes/note_service.ts +1 -1
  151. package/src/oracle_version.ts +3 -3
  152. package/src/pxe.ts +8 -5
  153. package/src/storage/backwards_compatibility_tests/__snapshots__/RecipientTaggingStore.json +11 -3
  154. package/src/storage/backwards_compatibility_tests/__snapshots__/SenderTaggingStore.json +12 -4
  155. package/src/storage/backwards_compatibility_tests/__snapshots__/opened_stores.json +1 -1
  156. package/src/storage/backwards_compatibility_tests/schema_tests.ts +30 -1
  157. package/src/storage/fact_store/index.ts +1 -0
  158. package/src/storage/fact_store/origin_state.ts +9 -0
  159. package/src/storage/metadata.ts +1 -1
  160. package/src/storage/store_identity.ts +72 -0
  161. package/src/storage/tagging_store/sender_tagging_store.ts +62 -15
  162. package/src/tagging/constants.ts +27 -5
  163. package/src/tagging/index.ts +1 -1
  164. package/src/tagging/recipient_sync/sync_tagged_private_logs.ts +103 -46
  165. package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +1 -1
  166. package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +6 -2
  167. package/src/tagging/testing/tag_query_test_utils.ts +11 -0
@@ -7,7 +7,7 @@ import { AppTaggingSecretKind, SiloedTag } from '@aztec/stdlib/logs';
7
7
  import type { BlockHeader } from '@aztec/stdlib/tx';
8
8
 
9
9
  import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
10
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
10
+ import { INITIAL_CONSTRAINED_PROBE_LEN, UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
11
11
  import { getAllPrivateLogsByTags } from '../get_all_logs_by_tags.js';
12
12
  import { findHighestIndexes } from './utils/find_highest_indexes.js';
13
13
 
@@ -62,9 +62,14 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
62
62
  * - The lower bound is `highestFinalizedIndex + 1`. The `highestAgedIndex` mechanism is unnecessary because
63
63
  * the nullifier chain prevents out-of-order index usage: no device can fill in a lower index after a higher
64
64
  * one is already on-chain.
65
- * - The scan stops at the first gap in the index sequence. If all indexes in the batch have logs, the window
66
- * advances. If a gap is found, the sequence has ended and no further logs exist.
67
- * - The upper bound is the same as unconstrained: `highestFinalizedIndex + WINDOW_LEN`.
65
+ * - Because the sequence is gapless, the scan stops at the first missing index: that gap proves the sequence has
66
+ * ended and no further logs exist. We exploit this with a doubling first-miss probe (see
67
+ * `INITIAL_CONSTRAINED_PROBE_LEN` in ../constants.ts), so a
68
+ * steady-state sync with no new logs costs two tags instead of the whole window. The probe length is in-memory
69
+ * state scoped to one sync call, so every sync restarts at the initial probe.
70
+ * - The upper bound is the same as unconstrained: `highestFinalizedIndex + WINDOW_LEN`. Advancing the probe is
71
+ * decoupled from persisting the finalized index, so unfinalized logs at the top of the run are still fetched
72
+ * while only the finalized prefix is persisted.
68
73
  *
69
74
  * # Batching across secrets
70
75
  *
@@ -109,19 +114,23 @@ export async function syncTaggedPrivateLogs(
109
114
 
110
115
  // Persist new indexes. If the finalized index moved forward, the window advances
111
116
  // and we need another round for this secret.
112
- const processForKind =
113
- pendingSecret.secret.kind === AppTaggingSecretKind.CONSTRAINED
114
- ? processConstrainedResults
115
- : processUnconstrainedResults;
116
-
117
- return await processForKind(
118
- pendingSecret,
119
- logsFoundWithSecret,
120
- taggingStore,
121
- currentTimestamp,
122
- finalizedBlockNumber,
123
- jobId,
124
- );
117
+ return pendingSecret.kind === AppTaggingSecretKind.CONSTRAINED
118
+ ? await processConstrainedResults(
119
+ pendingSecret,
120
+ logsFoundWithSecret,
121
+ taggingStore,
122
+ currentTimestamp,
123
+ finalizedBlockNumber,
124
+ jobId,
125
+ )
126
+ : await processUnconstrainedResults(
127
+ pendingSecret,
128
+ logsFoundWithSecret,
129
+ taggingStore,
130
+ currentTimestamp,
131
+ finalizedBlockNumber,
132
+ jobId,
133
+ );
125
134
  }),
126
135
  );
127
136
 
@@ -138,18 +147,29 @@ function getIndexRangesForSecrets(
138
147
  jobId: string,
139
148
  ): Promise<PendingSecret[]> {
140
149
  return Promise.all(
141
- secrets.map(async secret => {
150
+ secrets.map(async (secret): Promise<PendingSecret> => {
142
151
  const currentHighestFinalizedIndex = await taggingStore.getHighestFinalizedIndex(secret, jobId);
152
+ const boundEnd = (currentHighestFinalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
153
+
154
+ if (secret.kind === AppTaggingSecretKind.CONSTRAINED) {
155
+ // Constrained streams are gapless and resume at the finalized index, so probe a small initial window and stop
156
+ // at the first missing tag instead of always fetching the full window. The probe grows each round up to the
157
+ // window cap.
158
+ const start = currentHighestFinalizedIndex === undefined ? 0 : currentHighestFinalizedIndex + 1;
159
+ return {
160
+ kind: AppTaggingSecretKind.CONSTRAINED,
161
+ secret,
162
+ start,
163
+ end: Math.min(boundEnd, start + INITIAL_CONSTRAINED_PROBE_LEN),
164
+ boundEnd,
165
+ probeLen: INITIAL_CONSTRAINED_PROBE_LEN,
166
+ };
167
+ }
143
168
 
144
- const highestIndexBeforeStart =
145
- secret.kind === AppTaggingSecretKind.CONSTRAINED
146
- ? currentHighestFinalizedIndex
147
- : await taggingStore.getHighestAgedIndex(secret, jobId);
148
- const start = highestIndexBeforeStart === undefined ? 0 : highestIndexBeforeStart + 1;
149
-
150
- const end = (currentHighestFinalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
151
-
152
- return { secret, start, end };
169
+ // Unconstrained secrets can have gaps, so they scan the whole window starting past the highest aged index.
170
+ const highestAgedIndex = await taggingStore.getHighestAgedIndex(secret, jobId);
171
+ const start = highestAgedIndex === undefined ? 0 : highestAgedIndex + 1;
172
+ return { kind: AppTaggingSecretKind.UNCONSTRAINED, secret, start, end: boundEnd };
153
173
  }),
154
174
  );
155
175
  }
@@ -203,41 +223,58 @@ async function fetchLogsForSecrets(
203
223
  }
204
224
 
205
225
  /**
206
- * Processes fetched logs for a constrained secret. Constrained delivery guarantees contiguous index sequences,
207
- * so we scan from the start of the queried range and stop at the first missing index. Only `highestFinalizedIndex`
226
+ * Processes fetched logs for a constrained secret: persists the finalized index and advances the probe. See the
227
+ * "# Constrained secrets" section above for why the scan stops at the first missing index. Only `highestFinalizedIndex`
208
228
  * is tracked (no aged index).
209
229
  */
210
230
  async function processConstrainedResults(
211
- pending: PendingSecret,
231
+ pending: PendingConstrained,
212
232
  logsWithIndexes: LogWithIndex[],
213
233
  taggingStore: RecipientTaggingStore,
214
234
  currentTimestamp: bigint,
215
235
  finalizedBlockNumber: BlockNumber,
216
236
  jobId: string,
217
237
  ): Promise<PendingSecret | undefined> {
218
- // Find where the contiguous run of indexes ends. Constrained delivery guarantees there are no logs after the
219
- // first gap, so all logs in the batch are within this prefix.
238
+ // Find where the contiguous run of indexes ends; all logs in the batch fall within this prefix.
220
239
  const indexesWithLogs = new Set(logsWithIndexes.map(l => l.taggingIndex));
221
240
  let firstMissingIndex = pending.start;
222
241
  while (firstMissingIndex < pending.end && indexesWithLogs.has(firstMissingIndex)) {
223
242
  firstMissingIndex++;
224
243
  }
225
244
 
226
- // Finalize any logs before the gap. The nullifier for a constrained-delivery log is emitted in the same
227
- // transaction, guaranteeing the log cannot disappear once included, so we persist the highest finalized
228
- // index even when a gap stops the scan. This lets the next sync round skip already-finalized indexes.
245
+ // Persist the highest finalized index found. The nullifier for a constrained-delivery log is emitted in the same
246
+ // transaction, guaranteeing the log cannot disappear once included, so we persist even when a gap stops the scan.
247
+ // This lets the next sync round skip already-finalized indexes.
229
248
  const { highestFinalizedIndex } = findHighestIndexes(logsWithIndexes, currentTimestamp, finalizedBlockNumber);
230
-
231
249
  if (highestFinalizedIndex !== undefined) {
232
250
  await taggingStore.updateHighestFinalizedIndex(pending.secret, highestFinalizedIndex, jobId);
251
+ }
233
252
 
234
- if (firstMissingIndex >= pending.end) {
235
- return {
236
- secret: pending.secret,
237
- start: pending.end,
238
- end: highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1,
239
- };
240
- }
253
+ // Advancing the probe is decoupled from persisting the finalized index: keep scanning as long as the probe was
254
+ // entirely hits (no gap) and there is room before the protocol bound, even if none of those hits is finalized yet.
255
+ // Gating this on finalization would drop logs in unfinalized blocks, which sit at the top of the contiguous run.
256
+ // The bound re-anchors to any finalized index found this round.
257
+ const probeFullyConsumed = firstMissingIndex >= pending.end;
258
+ const boundEnd =
259
+ highestFinalizedIndex !== undefined
260
+ ? Math.max(pending.boundEnd, highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1)
261
+ : pending.boundEnd;
262
+
263
+ // Double the probe each round, capped at the window (see INITIAL_CONSTRAINED_PROBE_LEN in ../constants.ts).
264
+ // The queried range is already bounded by boundEnd (a probe can never reach
265
+ // more than WINDOW_LEN past the finalized frontier); this cap just keeps the stored length from growing unbounded
266
+ // once the probe saturates the window.
267
+ const nextProbeLen = Math.min(pending.probeLen * 2, UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN);
268
+
269
+ if (probeFullyConsumed && pending.end < boundEnd) {
270
+ return {
271
+ kind: AppTaggingSecretKind.CONSTRAINED,
272
+ secret: pending.secret,
273
+ start: pending.end,
274
+ end: Math.min(boundEnd, pending.end + nextProbeLen),
275
+ boundEnd,
276
+ probeLen: nextProbeLen,
277
+ };
241
278
  }
242
279
 
243
280
  return undefined;
@@ -248,7 +285,7 @@ async function processConstrainedResults(
248
285
  * if the window needs to advance, or undefined if this secret is done.
249
286
  */
250
287
  async function processUnconstrainedResults(
251
- pending: PendingSecret,
288
+ pending: PendingUnconstrained,
252
289
  logsWithIndexes: LogWithIndex[],
253
290
  taggingStore: RecipientTaggingStore,
254
291
  currentTimestamp: bigint,
@@ -282,19 +319,39 @@ async function processUnconstrainedResults(
282
319
 
283
320
  // For the next iteration we want to look only at indexes for which we have not yet fetched logs while
284
321
  // ensuring that we do not look further than WINDOW_LEN ahead of the highest finalized index.
322
+ const end = highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
285
323
  return {
324
+ kind: AppTaggingSecretKind.UNCONSTRAINED,
286
325
  secret: pending.secret,
287
326
  start: pending.end,
288
- end: highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1,
327
+ end,
289
328
  };
290
329
  }
291
330
 
292
- type PendingSecret = {
331
+ /** Working scan state common to both secret kinds: the half-open [start, end) tag-index range to query this round. */
332
+ type PendingSecretBase = {
293
333
  secret: AppTaggingSecret;
294
334
  start: number;
295
335
  end: number;
296
336
  };
297
337
 
338
+ /** Constrained scan state, carrying the doubling-probe bookkeeping that only the gapless constrained scan uses. */
339
+ type PendingConstrained = PendingSecretBase & {
340
+ kind: typeof AppTaggingSecretKind.CONSTRAINED;
341
+ // Exclusive upper bound on the indexes this secret may probe this sync (highest finalized index + WINDOW_LEN + 1, the
342
+ // protocol bound on how far ahead of finalized a log can sit). `end` grows toward it each round.
343
+ boundEnd: number;
344
+ // Intended probe length for the round that produced `end`. The queried span can be smaller when boundEnd caps it.
345
+ probeLen: number;
346
+ };
347
+
348
+ /** Unconstrained scan state: a plain window with no probe bookkeeping, since the scan always covers the full window. */
349
+ type PendingUnconstrained = PendingSecretBase & {
350
+ kind: typeof AppTaggingSecretKind.UNCONSTRAINED;
351
+ };
352
+
353
+ type PendingSecret = PendingConstrained | PendingUnconstrained;
354
+
298
355
  type LogWithIndex = {
299
356
  log: LogResult;
300
357
  taggingIndex: number;
@@ -74,7 +74,7 @@ export async function syncSenderTaggingIndexes(
74
74
  }
75
75
 
76
76
  // Receipts for pending tx hashes that the logs query just surfaced still need a sequential follow-up call.
77
- // `storePendingIndexes` is idempotent on (secret, txHash), so a re-discovered hash stays classified as known
77
+ // `mergePendingIndexes` is idempotent on (secret, txHash), so a re-discovered hash stays classified as known
78
78
  // and is not re-fetched here.
79
79
  const knownSet = new Set(knownPendingTxHashes.map(h => h.toString()));
80
80
  const newPendingTxHashes = allPendingTxHashes.filter(h => !knownSet.has(h.toString()));
@@ -36,11 +36,15 @@ export async function loadAndStoreNewTaggingIndexes(
36
36
  const txsForTags = await getTxsContainingTags(siloedTagsForWindow, aztecNode, anchorBlockHash);
37
37
  const txIndexesMap = getTxIndexesMap(txsForTags, start, siloedTagsForWindow.length);
38
38
 
39
- // Now we iterate over the map, construct the tagging index ranges and store them in the db.
39
+ // Now we iterate over the map, construct the tagging index ranges and store them in the db. A tx already tracked
40
+ // in the store is merged rather than range-checked: if this PXE sent the tx and it partially reverted, the chain
41
+ // only shows the surviving sub-range of the prove-time entry (the finalized receipt step of the sync owns
42
+ // resolving that difference), and a tx from another PXE may straddle a sync window boundary, in which case the
43
+ // entry is widened so the next index choice covers the full onchain range.
40
44
  for (const [txHashStr, indexes] of txIndexesMap.entries()) {
41
45
  const txHash = TxHash.fromString(txHashStr);
42
46
  const ranges = [{ extendedSecret, lowestIndex: Math.min(...indexes), highestIndex: Math.max(...indexes) }];
43
- await taggingStore.storePendingIndexes(ranges, txHash, jobId);
47
+ await taggingStore.mergePendingIndexes(ranges, txHash, jobId);
44
48
  }
45
49
  }
46
50
 
@@ -0,0 +1,11 @@
1
+ import { type AppTaggingSecret, type PrivateLogsQuery, SiloedTag, type TagQuery } from '@aztec/stdlib/logs';
2
+
3
+ /** Computes the siloed tag */
4
+ export function computeSiloedTagForIndex(secret: AppTaggingSecret, index: number): Promise<SiloedTag> {
5
+ return SiloedTag.compute({ extendedSecret: secret, index });
6
+ }
7
+
8
+ /** Extracts the bare-tag set from a query */
9
+ export function extractTags(query: PrivateLogsQuery): SiloedTag[] {
10
+ return query.tags.map((entry: TagQuery<SiloedTag>) => (entry instanceof SiloedTag ? entry : entry.tag));
11
+ }