@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
@@ -1,7 +1,7 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { isDefined } from '@aztec/foundation/types';
3
3
  import { AppTaggingSecretKind, SiloedTag } from '@aztec/stdlib/logs';
4
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
4
+ import { INITIAL_CONSTRAINED_PROBE_LEN, UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
5
5
  import { getAllPrivateLogsByTags } from '../get_all_logs_by_tags.js';
6
6
  import { findHighestIndexes } from './utils/find_highest_indexes.js';
7
7
  /**
@@ -55,9 +55,14 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
55
55
  * - The lower bound is `highestFinalizedIndex + 1`. The `highestAgedIndex` mechanism is unnecessary because
56
56
  * the nullifier chain prevents out-of-order index usage: no device can fill in a lower index after a higher
57
57
  * one is already on-chain.
58
- * - The scan stops at the first gap in the index sequence. If all indexes in the batch have logs, the window
59
- * advances. If a gap is found, the sequence has ended and no further logs exist.
60
- * - The upper bound is the same as unconstrained: `highestFinalizedIndex + WINDOW_LEN`.
58
+ * - Because the sequence is gapless, the scan stops at the first missing index: that gap proves the sequence has
59
+ * ended and no further logs exist. We exploit this with a doubling first-miss probe (see
60
+ * `INITIAL_CONSTRAINED_PROBE_LEN` in ../constants.ts), so a
61
+ * steady-state sync with no new logs costs two tags instead of the whole window. The probe length is in-memory
62
+ * state scoped to one sync call, so every sync restarts at the initial probe.
63
+ * - The upper bound is the same as unconstrained: `highestFinalizedIndex + WINDOW_LEN`. Advancing the probe is
64
+ * decoupled from persisting the finalized index, so unfinalized logs at the top of the run are still fetched
65
+ * while only the finalized prefix is persisted.
61
66
  *
62
67
  * # Batching across secrets
63
68
  *
@@ -87,8 +92,7 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
87
92
  allLogs.push(...logsFoundWithSecret.map(({ log })=>log));
88
93
  // Persist new indexes. If the finalized index moved forward, the window advances
89
94
  // and we need another round for this secret.
90
- const processForKind = pendingSecret.secret.kind === AppTaggingSecretKind.CONSTRAINED ? processConstrainedResults : processUnconstrainedResults;
91
- return await processForKind(pendingSecret, logsFoundWithSecret, taggingStore, currentTimestamp, finalizedBlockNumber, jobId);
95
+ return pendingSecret.kind === AppTaggingSecretKind.CONSTRAINED ? await processConstrainedResults(pendingSecret, logsFoundWithSecret, taggingStore, currentTimestamp, finalizedBlockNumber, jobId) : await processUnconstrainedResults(pendingSecret, logsFoundWithSecret, taggingStore, currentTimestamp, finalizedBlockNumber, jobId);
92
96
  }));
93
97
  pending = nextRound.filter(isDefined);
94
98
  }
@@ -97,13 +101,29 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
97
101
  /** Reads stored indexes for each secret and computes the initial index range to query. */ function getIndexRangesForSecrets(secrets, taggingStore, jobId) {
98
102
  return Promise.all(secrets.map(async (secret)=>{
99
103
  const currentHighestFinalizedIndex = await taggingStore.getHighestFinalizedIndex(secret, jobId);
100
- const highestIndexBeforeStart = secret.kind === AppTaggingSecretKind.CONSTRAINED ? currentHighestFinalizedIndex : await taggingStore.getHighestAgedIndex(secret, jobId);
101
- const start = highestIndexBeforeStart === undefined ? 0 : highestIndexBeforeStart + 1;
102
- const end = (currentHighestFinalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
104
+ const boundEnd = (currentHighestFinalizedIndex ?? 0) + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
105
+ if (secret.kind === AppTaggingSecretKind.CONSTRAINED) {
106
+ // Constrained streams are gapless and resume at the finalized index, so probe a small initial window and stop
107
+ // at the first missing tag instead of always fetching the full window. The probe grows each round up to the
108
+ // window cap.
109
+ const start = currentHighestFinalizedIndex === undefined ? 0 : currentHighestFinalizedIndex + 1;
110
+ return {
111
+ kind: AppTaggingSecretKind.CONSTRAINED,
112
+ secret,
113
+ start,
114
+ end: Math.min(boundEnd, start + INITIAL_CONSTRAINED_PROBE_LEN),
115
+ boundEnd,
116
+ probeLen: INITIAL_CONSTRAINED_PROBE_LEN
117
+ };
118
+ }
119
+ // Unconstrained secrets can have gaps, so they scan the whole window starting past the highest aged index.
120
+ const highestAgedIndex = await taggingStore.getHighestAgedIndex(secret, jobId);
121
+ const start = highestAgedIndex === undefined ? 0 : highestAgedIndex + 1;
103
122
  return {
123
+ kind: AppTaggingSecretKind.UNCONSTRAINED,
104
124
  secret,
105
125
  start,
106
- end
126
+ end: boundEnd
107
127
  };
108
128
  }));
109
129
  }
@@ -148,30 +168,43 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
148
168
  return logsPerSecret;
149
169
  }
150
170
  /**
151
- * Processes fetched logs for a constrained secret. Constrained delivery guarantees contiguous index sequences,
152
- * so we scan from the start of the queried range and stop at the first missing index. Only `highestFinalizedIndex`
171
+ * Processes fetched logs for a constrained secret: persists the finalized index and advances the probe. See the
172
+ * "# Constrained secrets" section above for why the scan stops at the first missing index. Only `highestFinalizedIndex`
153
173
  * is tracked (no aged index).
154
174
  */ async function processConstrainedResults(pending, logsWithIndexes, taggingStore, currentTimestamp, finalizedBlockNumber, jobId) {
155
- // Find where the contiguous run of indexes ends. Constrained delivery guarantees there are no logs after the
156
- // first gap, so all logs in the batch are within this prefix.
175
+ // Find where the contiguous run of indexes ends; all logs in the batch fall within this prefix.
157
176
  const indexesWithLogs = new Set(logsWithIndexes.map((l)=>l.taggingIndex));
158
177
  let firstMissingIndex = pending.start;
159
178
  while(firstMissingIndex < pending.end && indexesWithLogs.has(firstMissingIndex)){
160
179
  firstMissingIndex++;
161
180
  }
162
- // Finalize any logs before the gap. The nullifier for a constrained-delivery log is emitted in the same
163
- // transaction, guaranteeing the log cannot disappear once included, so we persist the highest finalized
164
- // index even when a gap stops the scan. This lets the next sync round skip already-finalized indexes.
181
+ // Persist the highest finalized index found. The nullifier for a constrained-delivery log is emitted in the same
182
+ // transaction, guaranteeing the log cannot disappear once included, so we persist even when a gap stops the scan.
183
+ // This lets the next sync round skip already-finalized indexes.
165
184
  const { highestFinalizedIndex } = findHighestIndexes(logsWithIndexes, currentTimestamp, finalizedBlockNumber);
166
185
  if (highestFinalizedIndex !== undefined) {
167
186
  await taggingStore.updateHighestFinalizedIndex(pending.secret, highestFinalizedIndex, jobId);
168
- if (firstMissingIndex >= pending.end) {
169
- return {
170
- secret: pending.secret,
171
- start: pending.end,
172
- end: highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1
173
- };
174
- }
187
+ }
188
+ // Advancing the probe is decoupled from persisting the finalized index: keep scanning as long as the probe was
189
+ // entirely hits (no gap) and there is room before the protocol bound, even if none of those hits is finalized yet.
190
+ // Gating this on finalization would drop logs in unfinalized blocks, which sit at the top of the contiguous run.
191
+ // The bound re-anchors to any finalized index found this round.
192
+ const probeFullyConsumed = firstMissingIndex >= pending.end;
193
+ const boundEnd = highestFinalizedIndex !== undefined ? Math.max(pending.boundEnd, highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1) : pending.boundEnd;
194
+ // Double the probe each round, capped at the window (see INITIAL_CONSTRAINED_PROBE_LEN in ../constants.ts).
195
+ // The queried range is already bounded by boundEnd (a probe can never reach
196
+ // more than WINDOW_LEN past the finalized frontier); this cap just keeps the stored length from growing unbounded
197
+ // once the probe saturates the window.
198
+ const nextProbeLen = Math.min(pending.probeLen * 2, UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN);
199
+ if (probeFullyConsumed && pending.end < boundEnd) {
200
+ return {
201
+ kind: AppTaggingSecretKind.CONSTRAINED,
202
+ secret: pending.secret,
203
+ start: pending.end,
204
+ end: Math.min(boundEnd, pending.end + nextProbeLen),
205
+ boundEnd,
206
+ probeLen: nextProbeLen
207
+ };
175
208
  }
176
209
  return undefined;
177
210
  }
@@ -195,9 +228,11 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
195
228
  await taggingStore.updateHighestFinalizedIndex(pending.secret, highestFinalizedIndex, jobId);
196
229
  // For the next iteration we want to look only at indexes for which we have not yet fetched logs while
197
230
  // ensuring that we do not look further than WINDOW_LEN ahead of the highest finalized index.
231
+ const end = highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1;
198
232
  return {
233
+ kind: AppTaggingSecretKind.UNCONSTRAINED,
199
234
  secret: pending.secret,
200
235
  start: pending.end,
201
- end: highestFinalizedIndex + UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN + 1
236
+ end
202
237
  };
203
238
  }
@@ -48,7 +48,7 @@ import { loadAndStoreNewTaggingIndexes } from './utils/load_and_store_new_taggin
48
48
  break;
49
49
  }
50
50
  // Receipts for pending tx hashes that the logs query just surfaced still need a sequential follow-up call.
51
- // `storePendingIndexes` is idempotent on (secret, txHash), so a re-discovered hash stays classified as known
51
+ // `mergePendingIndexes` is idempotent on (secret, txHash), so a re-discovered hash stays classified as known
52
52
  // and is not re-fetched here.
53
53
  const knownSet = new Set(knownPendingTxHashes.map((h)=>h.toString()));
54
54
  const newPendingTxHashes = allPendingTxHashes.filter((h)=>!knownSet.has(h.toString()));
@@ -16,4 +16,4 @@ import type { SenderTaggingStore } from '../../../storage/tagging_store/sender_t
16
16
  * preserving way.
17
17
  */
18
18
  export declare function loadAndStoreNewTaggingIndexes(extendedSecret: AppTaggingSecret, start: number, end: number, aztecNode: AztecNode, taggingStore: SenderTaggingStore, anchorBlockHash: BlockHash, jobId: string): Promise<void>;
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZF9hbmRfc3RvcmVfbmV3X3RhZ2dpbmdfaW5kZXhlcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3RhZ2dpbmcvc2VuZGVyX3N5bmMvdXRpbHMvbG9hZF9hbmRfc3RvcmVfbmV3X3RhZ2dpbmdfaW5kZXhlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBYSxNQUFNLG9CQUFvQixDQUFDO0FBR3RFLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0RBQXdELENBQUM7QUFHakc7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsd0JBQXNCLDZCQUE2QixDQUNqRCxjQUFjLEVBQUUsZ0JBQWdCLEVBQ2hDLEtBQUssRUFBRSxNQUFNLEVBQ2IsR0FBRyxFQUFFLE1BQU0sRUFDWCxTQUFTLEVBQUUsU0FBUyxFQUNwQixZQUFZLEVBQUUsa0JBQWtCLEVBQ2hDLGVBQWUsRUFBRSxTQUFTLEVBQzFCLEtBQUssRUFBRSxNQUFNLGlCQWdCZCJ9
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZF9hbmRfc3RvcmVfbmV3X3RhZ2dpbmdfaW5kZXhlcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3RhZ2dpbmcvc2VuZGVyX3N5bmMvdXRpbHMvbG9hZF9hbmRfc3RvcmVfbmV3X3RhZ2dpbmdfaW5kZXhlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBYSxNQUFNLG9CQUFvQixDQUFDO0FBR3RFLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0RBQXdELENBQUM7QUFHakc7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsd0JBQXNCLDZCQUE2QixDQUNqRCxjQUFjLEVBQUUsZ0JBQWdCLEVBQ2hDLEtBQUssRUFBRSxNQUFNLEVBQ2IsR0FBRyxFQUFFLE1BQU0sRUFDWCxTQUFTLEVBQUUsU0FBUyxFQUNwQixZQUFZLEVBQUUsa0JBQWtCLEVBQ2hDLGVBQWUsRUFBRSxTQUFTLEVBQzFCLEtBQUssRUFBRSxNQUFNLGlCQW9CZCJ9
@@ -1 +1 @@
1
- {"version":3,"file":"load_and_store_new_tagging_indexes.d.ts","sourceRoot":"","sources":["../../../../src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,KAAK,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wDAAwD,CAAC;AAGjG;;;;;;;;;;;;GAYG;AACH,wBAAsB,6BAA6B,CACjD,cAAc,EAAE,gBAAgB,EAChC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,kBAAkB,EAChC,eAAe,EAAE,SAAS,EAC1B,KAAK,EAAE,MAAM,iBAgBd"}
1
+ {"version":3,"file":"load_and_store_new_tagging_indexes.d.ts","sourceRoot":"","sources":["../../../../src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,KAAK,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wDAAwD,CAAC;AAGjG;;;;;;;;;;;;GAYG;AACH,wBAAsB,6BAA6B,CACjD,cAAc,EAAE,gBAAgB,EAChC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,kBAAkB,EAChC,eAAe,EAAE,SAAS,EAC1B,KAAK,EAAE,MAAM,iBAoBd"}
@@ -23,7 +23,11 @@ import { getAllPrivateLogsByTags } from '../../get_all_logs_by_tags.js';
23
23
  })));
24
24
  const txsForTags = await getTxsContainingTags(siloedTagsForWindow, aztecNode, anchorBlockHash);
25
25
  const txIndexesMap = getTxIndexesMap(txsForTags, start, siloedTagsForWindow.length);
26
- // Now we iterate over the map, construct the tagging index ranges and store them in the db.
26
+ // Now we iterate over the map, construct the tagging index ranges and store them in the db. A tx already tracked
27
+ // in the store is merged rather than range-checked: if this PXE sent the tx and it partially reverted, the chain
28
+ // only shows the surviving sub-range of the prove-time entry (the finalized receipt step of the sync owns
29
+ // resolving that difference), and a tx from another PXE may straddle a sync window boundary, in which case the
30
+ // entry is widened so the next index choice covers the full onchain range.
27
31
  for (const [txHashStr, indexes] of txIndexesMap.entries()){
28
32
  const txHash = TxHash.fromString(txHashStr);
29
33
  const ranges = [
@@ -33,7 +37,7 @@ import { getAllPrivateLogsByTags } from '../../get_all_logs_by_tags.js';
33
37
  highestIndex: Math.max(...indexes)
34
38
  }
35
39
  ];
36
- await taggingStore.storePendingIndexes(ranges, txHash, jobId);
40
+ await taggingStore.mergePendingIndexes(ranges, txHash, jobId);
37
41
  }
38
42
  }
39
43
  // Returns txs that used the given tags. A tag might have been used in multiple txs and for this reason we return
@@ -0,0 +1,6 @@
1
+ import { type AppTaggingSecret, type PrivateLogsQuery, SiloedTag } from '@aztec/stdlib/logs';
2
+ /** Computes the siloed tag */
3
+ export declare function computeSiloedTagForIndex(secret: AppTaggingSecret, index: number): Promise<SiloedTag>;
4
+ /** Extracts the bare-tag set from a query */
5
+ export declare function extractTags(query: PrivateLogsQuery): SiloedTag[];
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFnX3F1ZXJ5X3Rlc3RfdXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90YWdnaW5nL3Rlc3RpbmcvdGFnX3F1ZXJ5X3Rlc3RfdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssZ0JBQWdCLEVBQUUsS0FBSyxnQkFBZ0IsRUFBRSxTQUFTLEVBQWlCLE1BQU0sb0JBQW9CLENBQUM7QUFFNUcsOEJBQThCO0FBQzlCLHdCQUFnQix3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBRXBHO0FBRUQsNkNBQTZDO0FBQzdDLHdCQUFnQixXQUFXLENBQUMsS0FBSyxFQUFFLGdCQUFnQixHQUFHLFNBQVMsRUFBRSxDQUVoRSJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag_query_test_utils.d.ts","sourceRoot":"","sources":["../../../src/tagging/testing/tag_query_test_utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAE5G,8BAA8B;AAC9B,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAEpG;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,SAAS,EAAE,CAEhE"}
@@ -0,0 +1,10 @@
1
+ import { SiloedTag } from '@aztec/stdlib/logs';
2
+ /** Computes the siloed tag */ export function computeSiloedTagForIndex(secret, index) {
3
+ return SiloedTag.compute({
4
+ extendedSecret: secret,
5
+ index
6
+ });
7
+ }
8
+ /** Extracts the bare-tag set from a query */ export function extractTags(query) {
9
+ return query.tags.map((entry)=>entry instanceof SiloedTag ? entry : entry.tag);
10
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/pxe",
3
- "version": "0.0.1-commit.b8a057fa",
3
+ "version": "0.0.1-commit.be03c316",
4
4
  "type": "module",
5
5
  "typedocOptions": {
6
6
  "entryPoints": [
@@ -71,20 +71,20 @@
71
71
  ]
72
72
  },
73
73
  "dependencies": {
74
- "@aztec/bb-prover": "0.0.1-commit.b8a057fa",
75
- "@aztec/bb.js": "0.0.1-commit.b8a057fa",
76
- "@aztec/builder": "0.0.1-commit.b8a057fa",
77
- "@aztec/constants": "0.0.1-commit.b8a057fa",
78
- "@aztec/ethereum": "0.0.1-commit.b8a057fa",
79
- "@aztec/foundation": "0.0.1-commit.b8a057fa",
80
- "@aztec/key-store": "0.0.1-commit.b8a057fa",
81
- "@aztec/kv-store": "0.0.1-commit.b8a057fa",
82
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.b8a057fa",
83
- "@aztec/noir-types": "0.0.1-commit.b8a057fa",
84
- "@aztec/protocol-contracts": "0.0.1-commit.b8a057fa",
85
- "@aztec/simulator": "0.0.1-commit.b8a057fa",
86
- "@aztec/standard-contracts": "0.0.1-commit.b8a057fa",
87
- "@aztec/stdlib": "0.0.1-commit.b8a057fa",
74
+ "@aztec/bb-prover": "0.0.1-commit.be03c316",
75
+ "@aztec/bb.js": "0.0.1-commit.be03c316",
76
+ "@aztec/builder": "0.0.1-commit.be03c316",
77
+ "@aztec/constants": "0.0.1-commit.be03c316",
78
+ "@aztec/ethereum": "0.0.1-commit.be03c316",
79
+ "@aztec/foundation": "0.0.1-commit.be03c316",
80
+ "@aztec/key-store": "0.0.1-commit.be03c316",
81
+ "@aztec/kv-store": "0.0.1-commit.be03c316",
82
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.be03c316",
83
+ "@aztec/noir-types": "0.0.1-commit.be03c316",
84
+ "@aztec/protocol-contracts": "0.0.1-commit.be03c316",
85
+ "@aztec/simulator": "0.0.1-commit.be03c316",
86
+ "@aztec/standard-contracts": "0.0.1-commit.be03c316",
87
+ "@aztec/stdlib": "0.0.1-commit.be03c316",
88
88
  "koa": "^2.16.1",
89
89
  "koa-router": "^13.1.1",
90
90
  "lodash.omit": "^4.5.0",
@@ -93,8 +93,8 @@
93
93
  "viem": "npm:@aztec/viem@2.38.2"
94
94
  },
95
95
  "devDependencies": {
96
- "@aztec/noir-test-contracts.js": "0.0.1-commit.b8a057fa",
97
- "@aztec/world-state": "0.0.1-commit.b8a057fa",
96
+ "@aztec/noir-test-contracts.js": "0.0.1-commit.be03c316",
97
+ "@aztec/world-state": "0.0.1-commit.be03c316",
98
98
  "@jest/globals": "^30.0.0",
99
99
  "@types/jest": "^30.0.0",
100
100
  "@types/lodash.omit": "^4.5.7",
@@ -3,6 +3,7 @@ import { keccak256String } from '@aztec/foundation/crypto/keccak';
3
3
  import { dirname, join } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
 
6
+ import { ORACLE_REGISTRY } from '../contract_function_simulator/index.js';
6
7
  import { ORACLE_INTERFACE_HASH, ORACLE_VERSION_MAJOR } from '../oracle_version.js';
7
8
  import { getOracleRegistrySignature, readNumericGlobal } from './oracle_version_helpers.js';
8
9
 
@@ -10,7 +11,7 @@ import { getOracleRegistrySignature, readNumericGlobal } from './oracle_version_
10
11
  * Verifies that the Oracle interface matches the expected interface hash.
11
12
  *
12
13
  * The Oracle interface needs to be versioned to ensure compatibility between Aztec.nr and PXE. This function computes
13
- * a hash of the `ORACLE_REGISTRY` declaration (where each oracle's parameter names, parameter types, and return type
14
+ * a hash of `ORACLE_REGISTRY` (where each oracle's parameter names, parameter types, and return type
14
15
  * live) and compares it against a known hash. If they don't match, it means the interface has changed and the oracle
15
16
  * version needs to be bumped:
16
17
  * - If the change is backward-breaking (e.g. removing/renaming an oracle, or changing its params/return), bump
@@ -18,16 +19,8 @@ import { getOracleRegistrySignature, readNumericGlobal } from './oracle_version_
18
19
  * - If the change is an oracle addition (non-breaking), bump ORACLE_VERSION_MINOR.
19
20
  */
20
21
  function assertOracleInterfaceMatches(): void {
21
- // The script runs from dest/bin/ after compilation, so we go up to the package root then into src/ to find
22
- // the source file.
23
- const currentDir = dirname(fileURLToPath(import.meta.url));
24
- const packageRoot = dirname(dirname(currentDir)); // Go up from bin/ to pxe/
25
- const registrySourcePath = join(packageRoot, 'src/contract_function_simulator/oracle/oracle_registry.ts');
26
-
27
- const oracleInterfaceSignature = getOracleRegistrySignature(registrySourcePath, 'ORACLE_REGISTRY');
28
-
29
22
  // We use keccak256 here just because we already have it in the dependencies.
30
- const oracleInterfaceHash = keccak256String(oracleInterfaceSignature);
23
+ const oracleInterfaceHash = keccak256String(getOracleRegistrySignature(ORACLE_REGISTRY));
31
24
  if (oracleInterfaceHash !== ORACLE_INTERFACE_HASH) {
32
25
  throw new Error(
33
26
  `The Oracle interface has changed. Update ORACLE_INTERFACE_HASH to ${oracleInterfaceHash} in pxe/src/oracle_version.ts and bump the oracle version (ORACLE_VERSION_MAJOR for breaking changes, ORACLE_VERSION_MINOR for oracle additions).`,
package/src/bin/index.ts CHANGED
@@ -1,5 +1 @@
1
- export {
2
- getOracleInterfaceSignature,
3
- getOracleRegistrySignature,
4
- readNumericGlobal,
5
- } from './oracle_version_helpers.js';
1
+ export { getOracleRegistrySignature, readNumericGlobal } from './oracle_version_helpers.js';
@@ -1,75 +1,13 @@
1
- /* eslint-disable import-x/no-named-as-default-member */
2
1
  import { readFileSync } from 'fs';
3
- import ts from 'typescript';
4
2
 
5
- /**
6
- * Extracts method signatures from TypeScript classes or interfaces and returns a deterministic string representation.
7
- *
8
- * This is used to detect when an oracle interface changes so that the oracle version can be bumped. It works with both
9
- * class declarations (e.g. PXE's `Oracle` class) and interface declarations (e.g. TXE's `IAvmExecutionOracle`).
10
- *
11
- * @param sourcePath - Absolute path to the TypeScript source file to parse.
12
- * @param targets - Names of classes or interfaces to extract methods from.
13
- * @param excludedMembers - Method names to skip (e.g. non-oracle helpers like `constructor`).
14
- */
15
- export function getOracleInterfaceSignature(sourcePath: string, targets: string[], excludedMembers: string[]): string {
16
- const sourceCode = readFileSync(sourcePath, 'utf-8');
17
- const sourceFile = ts.createSourceFile(sourcePath, sourceCode, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
18
-
19
- const methodSignatures: string[] = [];
20
-
21
- function visit(node: ts.Node) {
22
- const isTarget =
23
- (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && targets.includes(node.name?.text ?? '');
24
-
25
- if (isTarget) {
26
- node.members.forEach(member => {
27
- if (
28
- (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) &&
29
- member.name &&
30
- ts.isIdentifier(member.name)
31
- ) {
32
- const methodName = member.name.text;
33
-
34
- if (excludedMembers.includes(methodName)) {
35
- return;
36
- }
37
-
38
- const paramSignatures: string[] = [];
39
- member.parameters.forEach(param => {
40
- const paramName = extractParameterName(param, sourceFile);
41
- const paramType = extractTypeString(param.type, sourceFile);
42
- paramSignatures.push(`${paramName}: ${paramType}`);
43
- });
44
-
45
- const returnType = extractTypeString(member.type, sourceFile);
46
-
47
- const signature = `${methodName}(${paramSignatures.join(', ')}): ${returnType}`;
48
- methodSignatures.push(signature);
49
- }
50
- });
51
- }
52
-
53
- ts.forEachChild(node, visit);
54
- }
55
-
56
- visit(sourceFile);
57
-
58
- methodSignatures.sort();
59
-
60
- return methodSignatures.join('');
61
- }
3
+ import type { OracleRegistryEntry } from '../contract_function_simulator/index.js';
62
4
 
63
5
  /**
64
- * Extracts a deterministic signature string from an oracle registry object literal (e.g. PXE's `ORACLE_REGISTRY`).
65
- *
66
- * Reads the registry declaration where each oracle's wire ABI lives: the ordered parameter names with their
67
- * `TypeMapping` expressions and the return type. The resulting hash is sensitive to parameter, type, and return
68
- * changes, not just oracle additions and removals.
6
+ * Extracts a deterministic signature string from an oracle registry (e.g. PXE's `ORACLE_REGISTRY`).
69
7
  *
70
- * Type expressions are captured as their source text (e.g. `OPTION(AZTEC_ADDRESS)`, `BOUNDED_VEC(NOTE)`), so the
71
- * signature tracks the composition of types. However, if the internal serialization logic of a `TypeMapping` constant
72
- * (e.g. `FIELD`) changes without the constant being renamed, the hash will not change.
8
+ * Reads the registry where each oracle's wire ABI lives: the ordered parameter names with their `TypeMapping` labels
9
+ * and the return type. The resulting hash is sensitive to parameter, type, and return changes, not just oracle
10
+ * additions and removals.
73
11
  *
74
12
  * @example
75
13
  * // Given a registry like:
@@ -79,32 +17,13 @@ export function getOracleInterfaceSignature(sourcePath: string, targets: string[
79
17
  * // } satisfies Record<string, OracleRegistryEntry>;
80
18
  * //
81
19
  * // Returns (sorted, newline-joined):
82
- * // "aztec_prv_bar(): void\naztec_utl_foo(a: U32): BOOL"
83
- *
84
- * @param sourcePath - Absolute path to the TypeScript source file declaring the registry.
85
- * @param registryName - Name of the registry constant to read (e.g. `ORACLE_REGISTRY`).
20
+ * // "aztec_prv_bar(): void\naztec_utl_foo(a: u32): bool"
86
21
  */
87
- export function getOracleRegistrySignature(sourcePath: string, registryName: string): string {
88
- const sourceCode = readFileSync(sourcePath, 'utf-8');
89
- const sourceFile = ts.createSourceFile(sourcePath, sourceCode, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
90
-
91
- const registry = findObjectLiteral(sourceFile, registryName);
92
- if (!registry) {
93
- throw new Error(`Could not find oracle registry '${registryName}' in ${sourcePath}.`);
94
- }
95
-
96
- const oracleSignatures = registry.properties.map(property => {
97
- if (!ts.isPropertyAssignment(property)) {
98
- throw new Error(
99
- `Unexpected member in oracle registry '${registryName}': ${property.getText(sourceFile)}. Spread elements ` +
100
- `are not supported.`,
101
- );
102
- }
103
-
104
- const oracleName = getPropertyName(property.name, sourceFile);
105
- const { params, returnType } = extractRegistryEntry(property.initializer, sourceFile);
106
- const paramSignatures = params.map(param => `${param.name}: ${param.type}`);
107
- return `${oracleName}(${paramSignatures.join(', ')}): ${returnType}`;
22
+ export function getOracleRegistrySignature(registry: Record<string, OracleRegistryEntry>): string {
23
+ const oracleSignatures = Object.entries(registry).map(([name, entry]) => {
24
+ const paramSignatures = entry.params.map(p => `${p.name}: ${p.type.label}`);
25
+ const returnType = entry.returnType === undefined ? 'void' : entry.returnType.label;
26
+ return `${name}(${paramSignatures.join(', ')}): ${returnType}`;
108
27
  });
109
28
 
110
29
  oracleSignatures.sort();
@@ -133,179 +52,3 @@ export function readNumericGlobal(sourcePath: string, name: string): number {
133
52
  }
134
53
  return Number(match[1]);
135
54
  }
136
-
137
- function extractParameterName(param: ts.ParameterDeclaration, sourceFile: ts.SourceFile): string {
138
- const name = param.name;
139
-
140
- if (ts.isIdentifier(name)) {
141
- return name.text;
142
- }
143
-
144
- if (ts.isArrayBindingPattern(name)) {
145
- if (name.elements.length > 0) {
146
- const element = name.elements[0];
147
- if (ts.isBindingElement(element)) {
148
- const elementName = element.name;
149
- if (ts.isIdentifier(elementName)) {
150
- return elementName.text;
151
- }
152
- if (ts.isArrayBindingPattern(elementName) || ts.isObjectBindingPattern(elementName)) {
153
- return elementName.getText(sourceFile);
154
- }
155
- }
156
- }
157
- return name.getText(sourceFile);
158
- }
159
-
160
- if (ts.isObjectBindingPattern(name)) {
161
- return name.getText(sourceFile);
162
- }
163
-
164
- return (name as ts.Node).getText(sourceFile);
165
- }
166
-
167
- /** Returns the source text of a type annotation, or `'void'` if absent. */
168
- function extractTypeString(typeNode: ts.TypeNode | undefined, sourceFile: ts.SourceFile): string {
169
- if (!typeNode) {
170
- return 'void';
171
- }
172
-
173
- return typeNode.getText(sourceFile).replace(/\s+/g, ' ').trim();
174
- }
175
-
176
- /**
177
- * Finds a top-level object-literal-valued constant by name, unwrapping `satisfies`/`as`/parenthesized wrappers.
178
- *
179
- * @example
180
- * // `const REGISTRY = { ... } satisfies Record<string, Entry>` => the `{ ... }` ObjectLiteralExpression
181
- */
182
- function findObjectLiteral(sourceFile: ts.SourceFile, name: string): ts.ObjectLiteralExpression | undefined {
183
- let result: ts.ObjectLiteralExpression | undefined;
184
-
185
- function visit(node: ts.Node) {
186
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name && node.initializer) {
187
- result = unwrapObjectLiteral(node.initializer);
188
- }
189
- ts.forEachChild(node, visit);
190
- }
191
-
192
- visit(sourceFile);
193
- return result;
194
- }
195
-
196
- /** Peels `satisfies`, `as`, and parenthesized wrappers off an expression to reach the underlying object literal. */
197
- function unwrapObjectLiteral(node: ts.Expression): ts.ObjectLiteralExpression | undefined {
198
- let current = node;
199
- while (ts.isSatisfiesExpression(current) || ts.isAsExpression(current) || ts.isParenthesizedExpression(current)) {
200
- current = current.expression;
201
- }
202
- return ts.isObjectLiteralExpression(current) ? current : undefined;
203
- }
204
-
205
- /**
206
- * Extracts the ordered `params` (names + type expressions) and `returnType` from a `makeEntry({ ... })` call.
207
- *
208
- * @example
209
- * // makeEntry({ params: [{ name: 'a', type: OPTION(FIELD) }], returnType: BOOL })
210
- * // => { params: [{ name: 'a', type: 'OPTION(FIELD)' }], returnType: 'BOOL' }
211
- * //
212
- * // makeEntry()
213
- * // => { params: [], returnType: 'void' }
214
- */
215
- function extractRegistryEntry(
216
- initializer: ts.Expression,
217
- sourceFile: ts.SourceFile,
218
- ): { params: { name: string; type: string }[]; returnType: string } {
219
- if (!ts.isCallExpression(initializer)) {
220
- throw new Error(`Expected a makeEntry(...) call but got: ${initializer.getText(sourceFile)}`);
221
- }
222
-
223
- const [arg] = initializer.arguments;
224
- if (arg === undefined) {
225
- return { params: [], returnType: 'void' };
226
- }
227
- if (!ts.isObjectLiteralExpression(arg)) {
228
- throw new Error(`Expected a makeEntry object argument but got: ${arg.getText(sourceFile)}`);
229
- }
230
-
231
- let params: { name: string; type: string }[] = [];
232
- let returnType = 'void';
233
-
234
- arg.properties.forEach(property => {
235
- if (!ts.isPropertyAssignment(property)) {
236
- throw new Error(`Unexpected makeEntry property: ${property.getText(sourceFile)}`);
237
- }
238
- const key = getPropertyName(property.name, sourceFile);
239
- if (key === 'params') {
240
- params = extractRegistryParams(property.initializer, sourceFile);
241
- } else if (key === 'returnType') {
242
- returnType = normalizeExpressionText(property.initializer, sourceFile);
243
- } else {
244
- throw new Error(`Unexpected makeEntry property '${key}'.`);
245
- }
246
- });
247
-
248
- return { params, returnType };
249
- }
250
-
251
- /**
252
- * Extracts `{ name, type }` pairs from the `params` array literal inside a `makeEntry` call.
253
- */
254
- function extractRegistryParams(
255
- initializer: ts.Expression,
256
- sourceFile: ts.SourceFile,
257
- ): { name: string; type: string }[] {
258
- if (!ts.isArrayLiteralExpression(initializer)) {
259
- throw new Error(`Expected a params array but got: ${initializer.getText(sourceFile)}`);
260
- }
261
-
262
- return initializer.elements.map(element => {
263
- if (!ts.isObjectLiteralExpression(element)) {
264
- throw new Error(`Expected a param object but got: ${element.getText(sourceFile)}`);
265
- }
266
-
267
- let name: string | undefined;
268
- let type: string | undefined;
269
- element.properties.forEach(property => {
270
- if (!ts.isPropertyAssignment(property)) {
271
- throw new Error(`Unexpected param property: ${property.getText(sourceFile)}`);
272
- }
273
- const key = getPropertyName(property.name, sourceFile);
274
- if (key === 'name') {
275
- if (!ts.isStringLiteralLike(property.initializer)) {
276
- throw new Error(`Expected a string literal param name but got: ${property.initializer.getText(sourceFile)}`);
277
- }
278
- name = property.initializer.text;
279
- } else if (key === 'type') {
280
- type = normalizeExpressionText(property.initializer, sourceFile);
281
- } else {
282
- throw new Error(`Unexpected param property '${key}'.`);
283
- }
284
- });
285
-
286
- if (name === undefined || type === undefined) {
287
- throw new Error(`Param missing 'name' or 'type': ${element.getText(sourceFile)}`);
288
- }
289
- return { name, type };
290
- });
291
- }
292
-
293
- /** Returns the text of an identifier or string-literal property name, throwing on computed or numeric names. */
294
- function getPropertyName(name: ts.PropertyName, sourceFile: ts.SourceFile): string {
295
- if (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) {
296
- return name.text;
297
- }
298
- throw new Error(`Unsupported property name: ${name.getText(sourceFile)}`);
299
- }
300
-
301
- /**
302
- * Returns the source text of an expression with all whitespace stripped for format-insensitive comparison.
303
- *
304
- * @example
305
- * // `OPTION(\n AZTEC_ADDRESS\n)` => `"OPTION(AZTEC_ADDRESS)"`
306
- */
307
- function normalizeExpressionText(node: ts.Expression, sourceFile: ts.SourceFile): string {
308
- // Type expressions are TypeMapping references and calls (identifiers, parentheses, commas, numbers) with no
309
- // meaningful whitespace, so we strip it entirely to keep the signature stable across reformatting.
310
- return node.getText(sourceFile).replace(/\s+/g, '');
311
- }
@@ -1,10 +1,10 @@
1
- import { isProtocolContract } from '@aztec/protocol-contracts';
2
1
  import type { FunctionCall, FunctionSelector } from '@aztec/stdlib/abi';
3
2
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
3
  import type { BlockHeader } from '@aztec/stdlib/tx';
5
4
 
6
5
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
7
6
  import type { ContractClassService } from './contract_class_service.js';
7
+ import { isSkipSyncContract } from './skip_sync_contracts.js';
8
8
 
9
9
  export async function syncScope(
10
10
  contractAddress: AztecAddress,
@@ -15,8 +15,8 @@ export async function syncScope(
15
15
  utilityExecutor: (privateSyncCall: FunctionCall, scopes: AztecAddress[]) => Promise<any>,
16
16
  scope: AztecAddress,
17
17
  ) {
18
- // Protocol contracts don't have private state to sync
19
- if (isProtocolContract(contractAddress)) {
18
+ // Some canonical contracts hold no private state, so there is nothing to sync (see `skipSyncContracts`).
19
+ if (isSkipSyncContract(contractAddress)) {
20
20
  return;
21
21
  }
22
22