@aztec/pxe 0.0.1-commit.6c91f13 → 0.0.1-commit.6d3c34e

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 (93) hide show
  1. package/dest/block_synchronizer/block_synchronizer.d.ts +4 -2
  2. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.js +6 -3
  4. package/dest/config/package_info.js +1 -1
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -3
  6. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  7. package/dest/contract_function_simulator/contract_function_simulator.js +7 -6
  8. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +3 -2
  9. package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts.map +1 -1
  10. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +5 -2
  11. package/dest/contract_function_simulator/oracle/private_execution.d.ts +1 -1
  12. package/dest/contract_function_simulator/oracle/private_execution.d.ts.map +1 -1
  13. package/dest/contract_function_simulator/oracle/private_execution.js +1 -2
  14. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +2 -17
  15. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  16. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +4 -32
  17. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +3 -2
  18. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  19. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +4 -2
  20. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  21. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  22. package/dest/entrypoints/client/bundle/utils.js +10 -1
  23. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  24. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  25. package/dest/entrypoints/client/lazy/utils.js +10 -1
  26. package/dest/entrypoints/pxe_creation_options.d.ts +3 -2
  27. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  28. package/dest/entrypoints/server/utils.d.ts +1 -1
  29. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  30. package/dest/entrypoints/server/utils.js +11 -7
  31. package/dest/events/event_service.d.ts +2 -2
  32. package/dest/events/event_service.d.ts.map +1 -1
  33. package/dest/events/event_service.js +2 -2
  34. package/dest/job_coordinator/job_coordinator.d.ts +74 -0
  35. package/dest/job_coordinator/job_coordinator.d.ts.map +1 -0
  36. package/dest/job_coordinator/job_coordinator.js +93 -0
  37. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts +2 -2
  38. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
  39. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.js +2 -2
  40. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  41. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  42. package/dest/private_kernel/private_kernel_execution_prover.js +3 -4
  43. package/dest/private_kernel/private_kernel_oracle.d.ts +3 -2
  44. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  45. package/dest/private_kernel/private_kernel_oracle_impl.d.ts +2 -2
  46. package/dest/private_kernel/private_kernel_oracle_impl.d.ts.map +1 -1
  47. package/dest/private_kernel/private_kernel_oracle_impl.js +2 -3
  48. package/dest/pxe.d.ts +2 -1
  49. package/dest/pxe.d.ts.map +1 -1
  50. package/dest/pxe.js +39 -20
  51. package/dest/storage/private_event_store/private_event_store.d.ts +7 -2
  52. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  53. package/dest/storage/private_event_store/private_event_store.js +57 -14
  54. package/dest/storage/tagging_store/sender_tagging_store.js +1 -1
  55. package/dest/tagging/constants.d.ts +2 -0
  56. package/dest/tagging/constants.d.ts.map +1 -0
  57. package/dest/tagging/constants.js +10 -0
  58. package/dest/tagging/index.d.ts +2 -2
  59. package/dest/tagging/index.d.ts.map +1 -1
  60. package/dest/tagging/index.js +1 -10
  61. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +1 -1
  62. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  63. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +2 -2
  64. package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +1 -1
  65. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts +1 -1
  66. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts.map +1 -1
  67. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.js +2 -2
  68. package/package.json +16 -16
  69. package/src/block_synchronizer/block_synchronizer.ts +5 -2
  70. package/src/config/package_info.ts +1 -1
  71. package/src/contract_function_simulator/contract_function_simulator.ts +10 -5
  72. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +4 -0
  73. package/src/contract_function_simulator/oracle/private_execution.ts +0 -2
  74. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +4 -36
  75. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +2 -0
  76. package/src/entrypoints/client/bundle/utils.ts +7 -1
  77. package/src/entrypoints/client/lazy/utils.ts +7 -2
  78. package/src/entrypoints/pxe_creation_options.ts +2 -1
  79. package/src/entrypoints/server/utils.ts +11 -15
  80. package/src/events/event_service.ts +2 -0
  81. package/src/job_coordinator/job_coordinator.ts +149 -0
  82. package/src/private_kernel/hints/build_private_kernel_reset_private_inputs.ts +1 -2
  83. package/src/private_kernel/private_kernel_execution_prover.ts +2 -4
  84. package/src/private_kernel/private_kernel_oracle.ts +2 -1
  85. package/src/private_kernel/private_kernel_oracle_impl.ts +2 -8
  86. package/src/pxe.ts +64 -19
  87. package/src/storage/private_event_store/private_event_store.ts +68 -14
  88. package/src/storage/tagging_store/sender_tagging_store.ts +1 -1
  89. package/src/tagging/constants.ts +10 -0
  90. package/src/tagging/index.ts +1 -11
  91. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +5 -2
  92. package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +1 -1
  93. package/src/tagging/sender_sync/utils/get_status_change_of_pending.ts +6 -2
package/src/pxe.ts CHANGED
@@ -60,9 +60,11 @@ import {
60
60
  } from './contract_function_simulator/contract_function_simulator.js';
61
61
  import { readCurrentClassId } from './contract_function_simulator/oracle/private_execution.js';
62
62
  import { ProxiedContractStoreFactory } from './contract_function_simulator/proxied_contract_data_source.js';
63
+ import { ProxiedNodeFactory } from './contract_function_simulator/proxied_node.js';
63
64
  import { PXEDebugUtils } from './debug/pxe_debug_utils.js';
64
65
  import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js';
65
66
  import { PrivateEventFilterValidator } from './events/private_event_filter_validator.js';
67
+ import { JobCoordinator } from './job_coordinator/job_coordinator.js';
66
68
  import {
67
69
  PrivateKernelExecutionProver,
68
70
  type PrivateKernelExecutionProverConfig,
@@ -107,6 +109,7 @@ export class PXE {
107
109
  private protocolContractsProvider: ProtocolContractsProvider,
108
110
  private log: Logger,
109
111
  private jobQueue: SerialQueue,
112
+ private jobCoordinator: JobCoordinator,
110
113
  public debug: PXEDebugUtils,
111
114
  ) {}
112
115
 
@@ -143,7 +146,17 @@ export class PXE {
143
146
  const capsuleStore = new CapsuleStore(store);
144
147
  const keyStore = new KeyStore(store);
145
148
  const tipsStore = new L2TipsKVStore(store, 'pxe');
146
- const synchronizer = new BlockSynchronizer(node, anchorBlockStore, noteStore, tipsStore, config, loggerOrSuffix);
149
+ const synchronizer = new BlockSynchronizer(
150
+ node,
151
+ anchorBlockStore,
152
+ noteStore,
153
+ privateEventStore,
154
+ tipsStore,
155
+ config,
156
+ loggerOrSuffix,
157
+ );
158
+
159
+ const jobCoordinator = new JobCoordinator(store);
147
160
 
148
161
  const debugUtils = new PXEDebugUtils(contractStore, noteStore);
149
162
 
@@ -168,6 +181,7 @@ export class PXE {
168
181
  protocolContractsProvider,
169
182
  log,
170
183
  jobQueue,
184
+ jobCoordinator,
171
185
  debugUtils,
172
186
  );
173
187
 
@@ -191,7 +205,7 @@ export class PXE {
191
205
  this.noteStore,
192
206
  this.keyStore,
193
207
  this.addressStore,
194
- this.node,
208
+ ProxiedNodeFactory.create(this.node),
195
209
  this.anchorBlockStore,
196
210
  this.senderTaggingStore,
197
211
  this.recipientTaggingStore,
@@ -222,7 +236,7 @@ export class PXE {
222
236
  *
223
237
  * Useful for tasks that cannot run concurrently, such as contract function simulation.
224
238
  */
225
- #putInJobQueue<T>(fn: () => Promise<T>): Promise<T> {
239
+ #putInJobQueue<T>(fn: (jobId: string) => Promise<T>): Promise<T> {
226
240
  // TODO(#12636): relax the conditions under which we forbid concurrency.
227
241
  if (this.jobQueue.length() != 0) {
228
242
  this.log.warn(
@@ -230,7 +244,22 @@ export class PXE {
230
244
  );
231
245
  }
232
246
 
233
- return this.jobQueue.put(fn);
247
+ return this.jobQueue.put(async () => {
248
+ const jobId = this.jobCoordinator.beginJob();
249
+ this.log.verbose(`Beginning job ${jobId}`);
250
+
251
+ try {
252
+ const result = await fn(jobId);
253
+ this.log.verbose(`Committing job ${jobId}`);
254
+
255
+ await this.jobCoordinator.commitJob(jobId);
256
+ return result;
257
+ } catch (err) {
258
+ this.log.verbose(`Aborting job ${jobId}`);
259
+ await this.jobCoordinator.abortJob(jobId);
260
+ throw err;
261
+ }
262
+ });
234
263
  }
235
264
 
236
265
  async #registerProtocolContracts() {
@@ -263,7 +292,8 @@ export class PXE {
263
292
  async #executePrivate(
264
293
  contractFunctionSimulator: ContractFunctionSimulator,
265
294
  txRequest: TxExecutionRequest,
266
- scopes?: AztecAddress[],
295
+ scopes: AztecAddress[] | undefined,
296
+ jobId: string,
267
297
  ): Promise<PrivateExecutionResult> {
268
298
  const { origin: contractAddress, functionSelector } = txRequest;
269
299
 
@@ -280,6 +310,7 @@ export class PXE {
280
310
  // contract entrypoint
281
311
  undefined, // senderForTags
282
312
  scopes,
313
+ jobId,
283
314
  );
284
315
  this.log.debug(`Private simulation completed for ${contractAddress.toString()}:${functionSelector}`);
285
316
  return result;
@@ -298,17 +329,19 @@ export class PXE {
298
329
  * @param authWitnesses - Authentication witnesses required for the function call.
299
330
  * @param scopes - Optional array of account addresses whose notes can be accessed in this call. Defaults to all
300
331
  * accounts if not specified.
332
+ * @param jobId - The job ID for staged writes.
301
333
  * @returns The simulation result containing the outputs of the utility function.
302
334
  */
303
335
  async #simulateUtility(
304
336
  contractFunctionSimulator: ContractFunctionSimulator,
305
337
  call: FunctionCall,
306
- authWitnesses?: AuthWitness[],
307
- scopes?: AztecAddress[],
338
+ authWitnesses: AuthWitness[] | undefined,
339
+ scopes: AztecAddress[] | undefined,
340
+ jobId: string,
308
341
  ) {
309
342
  try {
310
343
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
311
- return contractFunctionSimulator.runUtility(call, authWitnesses ?? [], anchorBlockHeader, scopes);
344
+ return contractFunctionSimulator.runUtility(call, authWitnesses ?? [], anchorBlockHeader, scopes, jobId);
312
345
  } catch (err) {
313
346
  if (err instanceof SimulationError) {
314
347
  await enrichSimulationError(err, this.contractStore, this.log);
@@ -657,14 +690,14 @@ export class PXE {
657
690
  let privateExecutionResult: PrivateExecutionResult;
658
691
  // We disable proving concurrently mostly out of caution, since it accesses some of our stores. Proving is so
659
692
  // computationally demanding that it'd be rare for someone to try to do it concurrently regardless.
660
- return this.#putInJobQueue(async () => {
693
+ return this.#putInJobQueue(async jobId => {
661
694
  const totalTimer = new Timer();
662
695
  try {
663
696
  const syncTimer = new Timer();
664
697
  await this.blockStateSynchronizer.sync();
665
698
  const syncTime = syncTimer.ms();
666
699
  const contractFunctionSimulator = this.#getSimulatorForTx();
667
- privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest);
700
+ privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, undefined, jobId);
668
701
 
669
702
  const {
670
703
  publicInputs,
@@ -741,7 +774,7 @@ export class PXE {
741
774
  skipProofGeneration: boolean = true,
742
775
  ): Promise<TxProfileResult> {
743
776
  // We disable concurrent profiles for consistency with simulateTx.
744
- return this.#putInJobQueue(async () => {
777
+ return this.#putInJobQueue(async jobId => {
745
778
  const totalTimer = new Timer();
746
779
  try {
747
780
  const txInfo = {
@@ -761,7 +794,12 @@ export class PXE {
761
794
  const syncTime = syncTimer.ms();
762
795
 
763
796
  const contractFunctionSimulator = this.#getSimulatorForTx();
764
- const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest);
797
+ const privateExecutionResult = await this.#executePrivate(
798
+ contractFunctionSimulator,
799
+ txRequest,
800
+ undefined,
801
+ jobId,
802
+ );
765
803
 
766
804
  const { executionSteps, timings: { proving } = {} } = await this.#prove(
767
805
  txRequest,
@@ -841,7 +879,7 @@ export class PXE {
841
879
  // We disable concurrent simulations since those might execute oracles which read and write to the PXE stores (e.g.
842
880
  // to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to
843
881
  // delete the same read value, or reading values that another simulation is currently modifying).
844
- return this.#putInJobQueue(async () => {
882
+ return this.#putInJobQueue(async jobId => {
845
883
  try {
846
884
  const totalTimer = new Timer();
847
885
  const txInfo = {
@@ -867,7 +905,7 @@ export class PXE {
867
905
  const skipKernels = overrides?.contracts !== undefined && Object.keys(overrides.contracts ?? {}).length > 0;
868
906
 
869
907
  // Execution of private functions only; no proving, and no kernel logic.
870
- const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes);
908
+ const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
871
909
 
872
910
  let publicInputs: PrivateKernelTailCircuitPublicInputs | undefined;
873
911
  let executionSteps: PrivateExecutionStep[] = [];
@@ -982,7 +1020,7 @@ export class PXE {
982
1020
  // We disable concurrent simulations since those might execute oracles which read and write to the PXE stores (e.g.
983
1021
  // to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to
984
1022
  // delete the same read value, or reading values that another simulation is currently modifying).
985
- return this.#putInJobQueue(async () => {
1023
+ return this.#putInJobQueue(async jobId => {
986
1024
  try {
987
1025
  const totalTimer = new Timer();
988
1026
  const syncTimer = new Timer();
@@ -992,10 +1030,16 @@ export class PXE {
992
1030
  const contractFunctionSimulator = this.#getSimulatorForTx();
993
1031
 
994
1032
  await this.contractStore.syncPrivateState(call.to, call.selector, privateSyncCall =>
995
- this.#simulateUtility(contractFunctionSimulator, privateSyncCall),
1033
+ this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
996
1034
  );
997
1035
 
998
- const executionResult = await this.#simulateUtility(contractFunctionSimulator, call, authwits ?? [], scopes);
1036
+ const executionResult = await this.#simulateUtility(
1037
+ contractFunctionSimulator,
1038
+ call,
1039
+ authwits ?? [],
1040
+ scopes,
1041
+ jobId,
1042
+ );
999
1043
  const functionTime = functionTimer.ms();
1000
1044
 
1001
1045
  const totalTime = totalTimer.ms();
@@ -1037,14 +1081,15 @@ export class PXE {
1037
1081
  * @returns - The packed events with block and tx metadata.
1038
1082
  */
1039
1083
  public getPrivateEvents(eventSelector: EventSelector, filter: PrivateEventFilter): Promise<PackedPrivateEvent[]> {
1040
- return this.#putInJobQueue(async () => {
1084
+ return this.#putInJobQueue(async jobId => {
1041
1085
  await this.blockStateSynchronizer.sync();
1042
1086
  const contractFunctionSimulator = this.#getSimulatorForTx();
1043
1087
 
1044
1088
  await this.contractStore.syncPrivateState(
1045
1089
  filter.contractAddress,
1046
1090
  null,
1047
- async privateSyncCall => await this.#simulateUtility(contractFunctionSimulator, privateSyncCall),
1091
+ async privateSyncCall =>
1092
+ await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
1048
1093
  );
1049
1094
 
1050
1095
  const sanitizedFilter = await new PrivateEventFilterValidator(this.anchorBlockStore).validate(filter);
@@ -2,7 +2,7 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
5
- import type { AztecAsyncArray, AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
5
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
6
6
  import type { EventSelector } from '@aztec/stdlib/abi';
7
7
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
8
8
  import { L2BlockHash } from '@aztec/stdlib/block';
@@ -19,11 +19,14 @@ export type PrivateEventStoreFilter = {
19
19
  };
20
20
 
21
21
  type PrivateEventEntry = {
22
+ randomness: Fr; // Note that this value is currently not being returned on queries and is therefore temporarily unused
22
23
  msgContent: Buffer;
23
24
  eventCommitmentIndex: number;
24
25
  l2BlockNumber: number;
25
26
  l2BlockHash: Buffer;
26
27
  txHash: Buffer;
28
+ /** The lookup key for #eventsByContractScopeSelector, used for cleanup during rollback */
29
+ lookupKey: string;
27
30
  };
28
31
 
29
32
  type PrivateEventMetadata = InTx & {
@@ -36,10 +39,12 @@ type PrivateEventMetadata = InTx & {
36
39
  */
37
40
  export class PrivateEventStore {
38
41
  #store: AztecAsyncKVStore;
39
- /** Array storing the actual private event log entries containing the log content and block number */
40
- #eventLogs: AztecAsyncArray<PrivateEventEntry>;
41
- /** Map from contract_address_scope_eventSelector to array of indices into #eventLogs for efficient lookup */
42
- #eventLogIndex: AztecAsyncMap<string, number[]>;
42
+ /** Map storing the actual private event log entries, keyed by eventCommitmentIndex */
43
+ #eventLogs: AztecAsyncMap<number, PrivateEventEntry>;
44
+ /** Map from contractAddress_scope_eventSelector to eventCommitmentIndex[] for efficient lookup */
45
+ #eventsByContractScopeSelector: AztecAsyncMap<string, number[]>;
46
+ /** Map from block number to eventCommitmentIndex[] for rollback support */
47
+ #eventsByBlockNumber: AztecAsyncMap<number, number[]>;
43
48
  /** Map from eventCommitmentIndex to boolean indicating if log has been seen. */
44
49
  #seenLogs: AztecAsyncMap<number, boolean>;
45
50
 
@@ -47,9 +52,10 @@ export class PrivateEventStore {
47
52
 
48
53
  constructor(store: AztecAsyncKVStore) {
49
54
  this.#store = store;
50
- this.#eventLogs = this.#store.openArray('private_event_logs');
51
- this.#eventLogIndex = this.#store.openMap('private_event_log_index');
55
+ this.#eventLogs = this.#store.openMap('private_event_logs');
56
+ this.#eventsByContractScopeSelector = this.#store.openMap('events_by_contract_scope_selector');
52
57
  this.#seenLogs = this.#store.openMap('seen_logs');
58
+ this.#eventsByBlockNumber = this.#store.openMap('events_by_block_number');
53
59
  }
54
60
 
55
61
  #keyFor(contractAddress: AztecAddress, scope: AztecAddress, eventSelector: EventSelector): string {
@@ -69,6 +75,7 @@ export class PrivateEventStore {
69
75
  */
70
76
  storePrivateEventLog(
71
77
  eventSelector: EventSelector,
78
+ randomness: Fr,
72
79
  msgContent: Fr[],
73
80
  eventCommitmentIndex: number,
74
81
  metadata: PrivateEventMetadata,
@@ -87,17 +94,21 @@ export class PrivateEventStore {
87
94
 
88
95
  this.logger.verbose('storing private event log', { contractAddress, scope, msgContent, l2BlockNumber });
89
96
 
90
- const index = await this.#eventLogs.lengthAsync();
91
- await this.#eventLogs.push({
97
+ await this.#eventLogs.set(eventCommitmentIndex, {
98
+ randomness,
92
99
  msgContent: serializeToBuffer(msgContent),
93
100
  l2BlockNumber,
94
101
  l2BlockHash: l2BlockHash.toBuffer(),
95
102
  eventCommitmentIndex,
96
103
  txHash: txHash.toBuffer(),
104
+ lookupKey: key,
97
105
  });
98
106
 
99
- const existingIndices = (await this.#eventLogIndex.getAsync(key)) || [];
100
- await this.#eventLogIndex.set(key, [...existingIndices, index]);
107
+ const existingIndices = (await this.#eventsByContractScopeSelector.getAsync(key)) || [];
108
+ await this.#eventsByContractScopeSelector.set(key, [...existingIndices, eventCommitmentIndex]);
109
+
110
+ const existingBlockIndices = (await this.#eventsByBlockNumber.getAsync(l2BlockNumber)) || [];
111
+ await this.#eventsByBlockNumber.set(l2BlockNumber, [...existingBlockIndices, eventCommitmentIndex]);
101
112
 
102
113
  // Mark this log as seen using eventCommitmentIndex
103
114
  await this.#seenLogs.set(eventCommitmentIndex, true);
@@ -123,10 +134,10 @@ export class PrivateEventStore {
123
134
 
124
135
  for (const scope of filter.scopes) {
125
136
  const key = this.#keyFor(filter.contractAddress, scope, eventSelector);
126
- const indices = (await this.#eventLogIndex.getAsync(key)) || [];
137
+ const eventCommitmentIndices = (await this.#eventsByContractScopeSelector.getAsync(key)) || [];
127
138
 
128
- for (const index of indices) {
129
- const entry = await this.#eventLogs.atAsync(index);
139
+ for (const eventCommitmentIndex of eventCommitmentIndices) {
140
+ const entry = await this.#eventLogs.getAsync(eventCommitmentIndex);
130
141
  if (!entry || entry.l2BlockNumber < filter.fromBlock || entry.l2BlockNumber >= filter.toBlock) {
131
142
  continue;
132
143
  }
@@ -159,4 +170,47 @@ export class PrivateEventStore {
159
170
  events.sort((a, b) => a.eventCommitmentIndex - b.eventCommitmentIndex);
160
171
  return events.map(ev => ev.event);
161
172
  }
173
+
174
+ /**
175
+ * Rolls back private events that were stored after a given `blockNumber` and up to `synchedBlockNumber` (the block
176
+ * number up to which PXE managed to sync before the reorg happened).
177
+ */
178
+ public async rollbackEventsAfterBlock(blockNumber: number, synchedBlockNumber: number): Promise<void> {
179
+ await this.#store.transactionAsync(async () => {
180
+ let removedCount = 0;
181
+
182
+ for (let block = blockNumber + 1; block <= synchedBlockNumber; block++) {
183
+ const indices = await this.#eventsByBlockNumber.getAsync(block);
184
+ if (indices) {
185
+ await this.#eventsByBlockNumber.delete(block);
186
+
187
+ for (const eventCommitmentIndex of indices) {
188
+ const entry = await this.#eventLogs.getAsync(eventCommitmentIndex);
189
+ if (!entry) {
190
+ throw new Error(`Event log not found for eventCommitmentIndex ${eventCommitmentIndex}`);
191
+ }
192
+
193
+ await this.#eventLogs.delete(eventCommitmentIndex);
194
+ await this.#seenLogs.delete(eventCommitmentIndex);
195
+
196
+ // Update #eventsByContractScopeSelector using the stored lookupKey
197
+ const existingIndices = await this.#eventsByContractScopeSelector.getAsync(entry.lookupKey);
198
+ if (!existingIndices || existingIndices.length === 0) {
199
+ throw new Error(`No indices found in #eventsByContractScopeSelector for key ${entry.lookupKey}`);
200
+ }
201
+ const filteredIndices = existingIndices.filter(idx => idx !== eventCommitmentIndex);
202
+ if (filteredIndices.length === 0) {
203
+ await this.#eventsByContractScopeSelector.delete(entry.lookupKey);
204
+ } else {
205
+ await this.#eventsByContractScopeSelector.set(entry.lookupKey, filteredIndices);
206
+ }
207
+
208
+ removedCount++;
209
+ }
210
+ }
211
+ }
212
+
213
+ this.logger.verbose(`Rolled back ${removedCount} private events after block ${blockNumber}`);
214
+ });
215
+ }
162
216
  }
@@ -3,7 +3,7 @@ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
3
3
  import type { DirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';
4
4
  import { TxHash } from '@aztec/stdlib/tx';
5
5
 
6
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../../tagging/index.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
@@ -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;
@@ -11,17 +11,7 @@
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';
25
15
 
26
16
  // Re-export tagging-related types from stdlib
27
17
  export { DirectionalAppTaggingSecret, Tag, SiloedTag } from '@aztec/stdlib/logs';
@@ -4,7 +4,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
4
4
  import type { DirectionalAppTaggingSecret, TxScopedL2Log } from '@aztec/stdlib/logs';
5
5
 
6
6
  import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
7
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../index.js';
7
+ import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
8
8
  import { findHighestIndexes } from './utils/find_highest_indexes.js';
9
9
  import { loadLogsForRange } from './utils/load_logs_for_range.js';
10
10
 
@@ -68,7 +68,10 @@ export async function loadPrivateLogsForSenderRecipientPair(
68
68
  throw new Error('Node failed to return latest block header when syncing logs');
69
69
  }
70
70
 
71
- [finalizedBlockNumber, currentTimestamp] = [l2Tips.finalized.number, latestBlockHeader.globalVariables.timestamp];
71
+ [finalizedBlockNumber, currentTimestamp] = [
72
+ l2Tips.finalized.block.number,
73
+ latestBlockHeader.globalVariables.timestamp,
74
+ ];
72
75
  }
73
76
 
74
77
  let start: number, end: number;
@@ -3,7 +3,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/server';
3
3
  import type { DirectionalAppTaggingSecret } from '@aztec/stdlib/logs';
4
4
 
5
5
  import type { SenderTaggingStore } from '../../storage/tagging_store/sender_tagging_store.js';
6
- import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../index.js';
6
+ import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
7
7
  import { getStatusChangeOfPending } from './utils/get_status_change_of_pending.js';
8
8
  import { loadAndStoreNewTaggingIndexes } from './utils/load_and_store_new_tagging_indexes.js';
9
9
 
@@ -10,7 +10,7 @@ export async function getStatusChangeOfPending(
10
10
  aztecNode: AztecNode,
11
11
  ): Promise<{ txHashesToFinalize: TxHash[]; txHashesToDrop: TxHash[] }> {
12
12
  // Get receipts for all pending tx hashes and the finalized block number.
13
- const [receipts, { finalized }] = await Promise.all([
13
+ const [receipts, tips] = await Promise.all([
14
14
  Promise.all(pending.map(pendingTxHash => aztecNode.getTxReceipt(pendingTxHash))),
15
15
  aztecNode.getL2Tips(),
16
16
  ]);
@@ -22,7 +22,11 @@ export async function getStatusChangeOfPending(
22
22
  const receipt = receipts[i];
23
23
  const txHash = pending[i];
24
24
 
25
- if (receipt.status === TxStatus.SUCCESS && receipt.blockNumber && receipt.blockNumber <= finalized.number) {
25
+ if (
26
+ receipt.status === TxStatus.SUCCESS &&
27
+ receipt.blockNumber &&
28
+ receipt.blockNumber <= tips.finalized.block.number
29
+ ) {
26
30
  // Tx has been included in a block and the corresponding block is finalized --> we mark the indexes as
27
31
  // finalized.
28
32
  txHashesToFinalize.push(txHash);