@aztec/pxe 0.0.1-commit.e310a4c8 → 0.0.1-commit.e558bd1c

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 (57) 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 +7 -1
  4. package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -2
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/contract_function_simulator.js +4 -2
  7. package/dest/contract_function_simulator/oracle/interfaces.d.ts +2 -2
  8. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/oracle/oracle.d.ts +2 -2
  10. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  11. package/dest/contract_function_simulator/oracle/oracle.js +20 -8
  12. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +4 -2
  13. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  14. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +6 -6
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +5 -5
  16. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +20 -18
  18. package/dest/contract_sync/contract_sync_service.d.ts +41 -0
  19. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -0
  20. package/dest/contract_sync/contract_sync_service.js +82 -0
  21. package/dest/contract_sync/helpers.d.ts +28 -0
  22. package/dest/contract_sync/helpers.d.ts.map +1 -0
  23. package/dest/contract_sync/{index.js → helpers.js} +13 -12
  24. package/dest/debug/pxe_debug_utils.d.ts +12 -7
  25. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  26. package/dest/debug/pxe_debug_utils.js +16 -12
  27. package/dest/entrypoints/server/index.d.ts +2 -2
  28. package/dest/entrypoints/server/index.d.ts.map +1 -1
  29. package/dest/entrypoints/server/index.js +1 -1
  30. package/dest/logs/log_service.d.ts +2 -2
  31. package/dest/logs/log_service.d.ts.map +1 -1
  32. package/dest/logs/log_service.js +2 -4
  33. package/dest/oracle_version.d.ts +2 -2
  34. package/dest/oracle_version.js +2 -2
  35. package/dest/pxe.d.ts +2 -1
  36. package/dest/pxe.d.ts.map +1 -1
  37. package/dest/pxe.js +23 -12
  38. package/dest/storage/note_store/note_store.d.ts +1 -1
  39. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  40. package/dest/storage/note_store/note_store.js +3 -0
  41. package/package.json +25 -16
  42. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  43. package/src/contract_function_simulator/contract_function_simulator.ts +3 -0
  44. package/src/contract_function_simulator/oracle/interfaces.ts +1 -1
  45. package/src/contract_function_simulator/oracle/oracle.ts +11 -4
  46. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +6 -5
  47. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +22 -19
  48. package/src/contract_sync/contract_sync_service.ts +129 -0
  49. package/src/contract_sync/{index.ts → helpers.ts} +15 -20
  50. package/src/debug/pxe_debug_utils.ts +46 -13
  51. package/src/entrypoints/server/index.ts +1 -1
  52. package/src/logs/log_service.ts +2 -2
  53. package/src/oracle_version.ts +2 -2
  54. package/src/pxe.ts +33 -13
  55. package/src/storage/note_store/note_store.ts +4 -0
  56. package/dest/contract_sync/index.d.ts +0 -23
  57. package/dest/contract_sync/index.d.ts.map +0 -1
package/dest/pxe.js CHANGED
@@ -13,7 +13,8 @@ import { BlockSynchronizer } from './block_synchronizer/index.js';
13
13
  import { BenchmarkedNodeFactory } from './contract_function_simulator/benchmarked_node.js';
14
14
  import { ContractFunctionSimulator, generateSimulatedProvingResult } from './contract_function_simulator/contract_function_simulator.js';
15
15
  import { ProxiedContractStoreFactory } from './contract_function_simulator/proxied_contract_data_source.js';
16
- import { ensureContractSynced, readCurrentClassId } from './contract_sync/index.js';
16
+ import { ContractSyncService } from './contract_sync/contract_sync_service.js';
17
+ import { readCurrentClassId } from './contract_sync/helpers.js';
17
18
  import { PXEDebugUtils } from './debug/pxe_debug_utils.js';
18
19
  import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js';
19
20
  import { PrivateEventFilterValidator } from './events/private_event_filter_validator.js';
@@ -45,6 +46,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
45
46
  recipientTaggingStore;
46
47
  addressStore;
47
48
  privateEventStore;
49
+ contractSyncService;
48
50
  simulator;
49
51
  proverEnabled;
50
52
  proofCreator;
@@ -53,7 +55,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
53
55
  jobQueue;
54
56
  jobCoordinator;
55
57
  debug;
56
- constructor(node, blockStateSynchronizer, keyStore, contractStore, noteStore, capsuleStore, anchorBlockStore, senderTaggingStore, senderAddressBookStore, recipientTaggingStore, addressStore, privateEventStore, simulator, proverEnabled, proofCreator, protocolContractsProvider, log, jobQueue, jobCoordinator, debug){
58
+ constructor(node, blockStateSynchronizer, keyStore, contractStore, noteStore, capsuleStore, anchorBlockStore, senderTaggingStore, senderAddressBookStore, recipientTaggingStore, addressStore, privateEventStore, contractSyncService, simulator, proverEnabled, proofCreator, protocolContractsProvider, log, jobQueue, jobCoordinator, debug){
57
59
  this.node = node;
58
60
  this.blockStateSynchronizer = blockStateSynchronizer;
59
61
  this.keyStore = keyStore;
@@ -66,6 +68,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
66
68
  this.recipientTaggingStore = recipientTaggingStore;
67
69
  this.addressStore = addressStore;
68
70
  this.privateEventStore = privateEventStore;
71
+ this.contractSyncService = contractSyncService;
69
72
  this.simulator = simulator;
70
73
  this.proverEnabled = proverEnabled;
71
74
  this.proofCreator = proofCreator;
@@ -97,19 +100,21 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
97
100
  const capsuleStore = new CapsuleStore(store);
98
101
  const keyStore = new KeyStore(store);
99
102
  const tipsStore = new L2TipsKVStore(store, 'pxe');
100
- const synchronizer = new BlockSynchronizer(node, store, anchorBlockStore, noteStore, privateEventStore, tipsStore, config, bindings);
103
+ const contractSyncService = new ContractSyncService(node, contractStore, noteStore, createLogger('pxe:contract_sync', bindings));
104
+ const synchronizer = new BlockSynchronizer(node, store, anchorBlockStore, noteStore, privateEventStore, tipsStore, contractSyncService, config, bindings);
101
105
  const jobCoordinator = new JobCoordinator(store, bindings);
102
106
  jobCoordinator.registerStores([
103
107
  capsuleStore,
104
108
  senderTaggingStore,
105
109
  recipientTaggingStore,
106
110
  privateEventStore,
107
- noteStore
111
+ noteStore,
112
+ contractSyncService
108
113
  ]);
109
- const debugUtils = new PXEDebugUtils(contractStore, noteStore, synchronizer, anchorBlockStore);
114
+ const debugUtils = new PXEDebugUtils(contractSyncService, noteStore, synchronizer, anchorBlockStore);
110
115
  const jobQueue = new SerialQueue();
111
- const pxe = new PXE(node, synchronizer, keyStore, contractStore, noteStore, capsuleStore, anchorBlockStore, senderTaggingStore, senderAddressBookStore, recipientTaggingStore, addressStore, privateEventStore, simulator, proverEnabled, proofCreator, protocolContractsProvider, log, jobQueue, jobCoordinator, debugUtils);
112
- debugUtils.setPXE(pxe, pxe.#putInJobQueue.bind(pxe));
116
+ const pxe = new PXE(node, synchronizer, keyStore, contractStore, noteStore, capsuleStore, anchorBlockStore, senderTaggingStore, senderAddressBookStore, recipientTaggingStore, addressStore, privateEventStore, contractSyncService, simulator, proverEnabled, proofCreator, protocolContractsProvider, log, jobQueue, jobCoordinator, debugUtils);
117
+ debugUtils.setPXEHelpers(pxe.#putInJobQueue.bind(pxe), pxe.#getSimulatorForTx.bind(pxe), pxe.#simulateUtility.bind(pxe));
113
118
  pxe.jobQueue.start();
114
119
  await pxe.#registerProtocolContracts();
115
120
  const info = await node.getNodeInfo();
@@ -119,7 +124,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
119
124
  // Internal methods
120
125
  #getSimulatorForTx(overrides) {
121
126
  const proxyContractStore = ProxiedContractStoreFactory.create(this.contractStore, overrides?.contracts);
122
- return new ContractFunctionSimulator(proxyContractStore, this.noteStore, this.keyStore, this.addressStore, BenchmarkedNodeFactory.create(this.node), this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.simulator);
127
+ return new ContractFunctionSimulator(proxyContractStore, this.noteStore, this.keyStore, this.addressStore, BenchmarkedNodeFactory.create(this.node), this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.simulator, this.contractSyncService);
123
128
  }
124
129
  #contextualizeError(err, ...context) {
125
130
  let contextStr = '';
@@ -175,7 +180,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
175
180
  const { origin: contractAddress, functionSelector } = txRequest;
176
181
  try {
177
182
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
178
- await ensureContractSynced(contractAddress, functionSelector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), this.node, this.contractStore, anchorBlockHeader);
183
+ await this.contractSyncService.ensureContractSynced(contractAddress, functionSelector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), anchorBlockHeader, jobId);
179
184
  const result = await contractFunctionSimulator.run(txRequest, contractAddress, functionSelector, undefined, anchorBlockHeader, // The sender for tags is set by contracts, typically by an account
180
185
  // contract entrypoint
181
186
  undefined, scopes, jobId);
@@ -586,7 +591,13 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
586
591
  // Temporary: in case there are overrides, we have to skip the kernels or validations
587
592
  // will fail. Consider handing control to the user/wallet on whether they want to run them
588
593
  // or not.
589
- const skipKernels = overrides?.contracts !== undefined && Object.keys(overrides.contracts ?? {}).length > 0;
594
+ const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined;
595
+ const hasOverriddenContracts = overriddenContracts !== undefined && overriddenContracts.size > 0;
596
+ const skipKernels = hasOverriddenContracts;
597
+ // Set overridden contracts on the sync service so it knows to skip syncing them
598
+ if (hasOverriddenContracts) {
599
+ this.contractSyncService.setOverriddenContracts(jobId, overriddenContracts);
600
+ }
590
601
  // Execution of private functions only; no proving, and no kernel logic.
591
602
  const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
592
603
  let publicInputs;
@@ -677,7 +688,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
677
688
  const functionTimer = new Timer();
678
689
  const contractFunctionSimulator = this.#getSimulatorForTx();
679
690
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
680
- await ensureContractSynced(call.to, call.selector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), this.node, this.contractStore, anchorBlockHeader);
691
+ await this.contractSyncService.ensureContractSynced(call.to, call.selector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), anchorBlockHeader, jobId);
681
692
  const executionResult = await this.#simulateUtility(contractFunctionSimulator, call, authwits ?? [], scopes, jobId);
682
693
  const functionTime = functionTimer.ms();
683
694
  const totalTime = totalTimer.ms();
@@ -727,7 +738,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
727
738
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
728
739
  anchorBlockNumber = anchorBlockHeader.getBlockNumber();
729
740
  const contractFunctionSimulator = this.#getSimulatorForTx();
730
- await ensureContractSynced(filter.contractAddress, null, async (privateSyncCall)=>await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), this.node, this.contractStore, anchorBlockHeader);
741
+ await this.contractSyncService.ensureContractSynced(filter.contractAddress, null, async (privateSyncCall)=>await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), anchorBlockHeader, jobId);
731
742
  });
732
743
  // anchorBlockNumber is set during the job and fixed to whatever it is after a block sync
733
744
  const sanitizedFilter = new PrivateEventFilterValidator(anchorBlockNumber).validate(filter);
@@ -80,4 +80,4 @@ export declare class NoteStore implements StagedStore {
80
80
  commit(jobId: string): Promise<void>;
81
81
  discardStaged(jobId: string): Promise<void>;
82
82
  }
83
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90ZV9zdG9yZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N0b3JhZ2Uvbm90ZV9zdG9yZS9ub3RlX3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFxQyxNQUFNLGlCQUFpQixDQUFDO0FBQzVGLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxPQUFPLEVBQWMsS0FBSyxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUzRSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUc1RTs7Ozs7SUFLSTtBQUNKLHFCQUFhLFNBQVUsWUFBVyxXQUFXOztJQUMzQyxRQUFRLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBVTtJQStCcEMsWUFBWSxLQUFLLEVBQUUsaUJBQWlCLEVBUW5DO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0ksUUFBUSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBYXJGO0lBY0Q7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxRQUFRLENBQUMsTUFBTSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQTZGL0Q7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILGVBQWUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FxQ2hGO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDVSxRQUFRLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQU1wRjtJQTZFRDs7Ozs7Ozs7O09BU0c7SUFDRyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBVXpDO0lBRUQsYUFBYSxDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUcxQztDQWtDRiJ9
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90ZV9zdG9yZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N0b3JhZ2Uvbm90ZV9zdG9yZS9ub3RlX3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFxQyxNQUFNLGlCQUFpQixDQUFDO0FBQzVGLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxPQUFPLEVBQWMsS0FBSyxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUzRSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUc1RTs7Ozs7SUFLSTtBQUNKLHFCQUFhLFNBQVUsWUFBVyxXQUFXOztJQUMzQyxRQUFRLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBVTtJQStCcEMsWUFBWSxLQUFLLEVBQUUsaUJBQWlCLEVBUW5DO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0ksUUFBUSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBYXJGO0lBY0Q7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxRQUFRLENBQUMsTUFBTSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQTZGL0Q7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILGVBQWUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0F5Q2hGO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDVSxRQUFRLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQU1wRjtJQTZFRDs7Ozs7Ozs7O09BU0c7SUFDRyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBVXpDO0lBRUQsYUFBYSxDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUcxQztDQWtDRiJ9
@@ -1 +1 @@
1
- {"version":3,"file":"note_store.d.ts","sourceRoot":"","sources":["../../../src/storage/note_store/note_store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAqC,MAAM,iBAAiB,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAG5E;;;;;IAKI;AACJ,qBAAa,SAAU,YAAW,WAAW;;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAU;IA+BpC,YAAY,KAAK,EAAE,iBAAiB,EAQnC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAarF;IAcD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA6F/D;IAED;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAqChF;IAED;;;;;;;;;;;OAWG;IACU,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpF;IA6ED;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUzC;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1C;CAkCF"}
1
+ {"version":3,"file":"note_store.d.ts","sourceRoot":"","sources":["../../../src/storage/note_store/note_store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAqC,MAAM,iBAAiB,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAG5E;;;;;IAKI;AACJ,qBAAa,SAAU,YAAW,WAAW;;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAU;IA+BpC,YAAY,KAAK,EAAE,iBAAiB,EAQnC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAarF;IAcD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA6F/D;IAED;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAyChF;IAED;;;;;;;;;;;OAWG;IACU,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpF;IA6ED;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUzC;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1C;CAkCF"}
@@ -173,6 +173,9 @@ import { StoredNote } from './stored_note.js';
173
173
  if (nullifiers.length === 0) {
174
174
  return Promise.resolve([]);
175
175
  }
176
+ if (nullifiers.some((n)=>n.l2BlockNumber === 0)) {
177
+ return Promise.reject(new Error('applyNullifiers: nullifiers cannot have been emitted at block 0'));
178
+ }
176
179
  return this.#withJobLock(jobId, ()=>this.#store.transactionAsync(async ()=>{
177
180
  const notesToNullify = await Promise.all(nullifiers.map(async (nullifierInBlock)=>{
178
181
  const nullifier = nullifierInBlock.data.toString();
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "@aztec/pxe",
3
- "version": "0.0.1-commit.e310a4c8",
3
+ "version": "0.0.1-commit.e558bd1c",
4
4
  "type": "module",
5
+ "typedocOptions": {
6
+ "entryPoints": [
7
+ "./src/entrypoints/server/index.ts",
8
+ "./src/entrypoints/client/lazy/index.ts",
9
+ "./src/config/index.ts"
10
+ ],
11
+ "name": "PXE",
12
+ "tsconfig": "./tsconfig.json"
13
+ },
5
14
  "exports": {
6
15
  "./server": "./dest/entrypoints/server/index.js",
7
16
  "./client/lazy": "./dest/entrypoints/client/lazy/index.js",
@@ -61,19 +70,19 @@
61
70
  ]
62
71
  },
63
72
  "dependencies": {
64
- "@aztec/bb-prover": "0.0.1-commit.e310a4c8",
65
- "@aztec/bb.js": "0.0.1-commit.e310a4c8",
66
- "@aztec/builder": "0.0.1-commit.e310a4c8",
67
- "@aztec/constants": "0.0.1-commit.e310a4c8",
68
- "@aztec/ethereum": "0.0.1-commit.e310a4c8",
69
- "@aztec/foundation": "0.0.1-commit.e310a4c8",
70
- "@aztec/key-store": "0.0.1-commit.e310a4c8",
71
- "@aztec/kv-store": "0.0.1-commit.e310a4c8",
72
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.e310a4c8",
73
- "@aztec/noir-types": "0.0.1-commit.e310a4c8",
74
- "@aztec/protocol-contracts": "0.0.1-commit.e310a4c8",
75
- "@aztec/simulator": "0.0.1-commit.e310a4c8",
76
- "@aztec/stdlib": "0.0.1-commit.e310a4c8",
73
+ "@aztec/bb-prover": "0.0.1-commit.e558bd1c",
74
+ "@aztec/bb.js": "0.0.1-commit.e558bd1c",
75
+ "@aztec/builder": "0.0.1-commit.e558bd1c",
76
+ "@aztec/constants": "0.0.1-commit.e558bd1c",
77
+ "@aztec/ethereum": "0.0.1-commit.e558bd1c",
78
+ "@aztec/foundation": "0.0.1-commit.e558bd1c",
79
+ "@aztec/key-store": "0.0.1-commit.e558bd1c",
80
+ "@aztec/kv-store": "0.0.1-commit.e558bd1c",
81
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.e558bd1c",
82
+ "@aztec/noir-types": "0.0.1-commit.e558bd1c",
83
+ "@aztec/protocol-contracts": "0.0.1-commit.e558bd1c",
84
+ "@aztec/simulator": "0.0.1-commit.e558bd1c",
85
+ "@aztec/stdlib": "0.0.1-commit.e558bd1c",
77
86
  "koa": "^2.16.1",
78
87
  "koa-router": "^13.1.1",
79
88
  "lodash.omit": "^4.5.0",
@@ -82,8 +91,8 @@
82
91
  "viem": "npm:@aztec/viem@2.38.2"
83
92
  },
84
93
  "devDependencies": {
85
- "@aztec/merkle-tree": "0.0.1-commit.e310a4c8",
86
- "@aztec/noir-test-contracts.js": "0.0.1-commit.e310a4c8",
94
+ "@aztec/merkle-tree": "0.0.1-commit.e558bd1c",
95
+ "@aztec/noir-test-contracts.js": "0.0.1-commit.e558bd1c",
87
96
  "@jest/globals": "^30.0.0",
88
97
  "@types/jest": "^30.0.0",
89
98
  "@types/lodash.omit": "^4.5.7",
@@ -7,6 +7,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
7
7
  import type { BlockHeader } from '@aztec/stdlib/tx';
8
8
 
9
9
  import type { BlockSynchronizerConfig } from '../config/index.js';
10
+ import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
10
11
  import type { AnchorBlockStore } from '../storage/anchor_block_store/anchor_block_store.js';
11
12
  import type { NoteStore } from '../storage/note_store/note_store.js';
12
13
  import type { PrivateEventStore } from '../storage/private_event_store/private_event_store.js';
@@ -28,6 +29,7 @@ export class BlockSynchronizer implements L2BlockStreamEventHandler {
28
29
  private noteStore: NoteStore,
29
30
  private privateEventStore: PrivateEventStore,
30
31
  private l2TipsStore: L2TipsKVStore,
32
+ private contractSyncService: ContractSyncService,
31
33
  private config: Partial<BlockSynchronizerConfig> = {},
32
34
  bindings?: LoggerBindings,
33
35
  ) {
@@ -125,6 +127,10 @@ export class BlockSynchronizer implements L2BlockStreamEventHandler {
125
127
 
126
128
  /** Updates the anchor block header to the target block */
127
129
  private async updateAnchorBlockHeader(blockHeader: BlockHeader) {
130
+ // Whenever the anchor block header is updated, we need to synchronize the private state of contracts again.
131
+ // Therefore, we clear the contract synchronization cache here such that the sync is re-triggered upon new
132
+ // execution.
133
+ this.contractSyncService.wipe();
128
134
  this.log.verbose(`Updated pxe last block to ${blockHeader.getBlockNumber()}`, blockHeader.toInspect());
129
135
  await this.anchorBlockStore.setHeader(blockHeader);
130
136
  }
@@ -72,6 +72,7 @@ import {
72
72
  getFinalMinRevertibleSideEffectCounter,
73
73
  } from '@aztec/stdlib/tx';
74
74
 
75
+ import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
75
76
  import type { AddressStore } from '../storage/address_store/address_store.js';
76
77
  import type { CapsuleStore } from '../storage/capsule_store/capsule_store.js';
77
78
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
@@ -107,6 +108,7 @@ export class ContractFunctionSimulator {
107
108
  private capsuleStore: CapsuleStore,
108
109
  private privateEventStore: PrivateEventStore,
109
110
  private simulator: CircuitSimulator,
111
+ private contractSyncService: ContractSyncService,
110
112
  ) {
111
113
  this.log = createLogger('simulator');
112
114
  }
@@ -186,6 +188,7 @@ export class ContractFunctionSimulator {
186
188
  this.senderAddressBookStore,
187
189
  this.capsuleStore,
188
190
  this.privateEventStore,
191
+ this.contractSyncService,
189
192
  jobId,
190
193
  0, // totalPublicArgsCount
191
194
  startSideEffectCounter,
@@ -85,7 +85,7 @@ export interface IUtilityExecutionOracle {
85
85
  nullifier: Fr,
86
86
  ): Promise<NullifierMembershipWitness | undefined>;
87
87
  utilityGetBlockHeader(blockNumber: BlockNumber): Promise<BlockHeader | undefined>;
88
- utilityGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress>;
88
+ utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress | undefined>;
89
89
  utilityGetAuthWitness(messageHash: Fr): Promise<Fr[] | undefined>;
90
90
  utilityGetNotes(
91
91
  owner: AztecAddress | undefined,
@@ -248,12 +248,19 @@ export class Oracle {
248
248
  return [witness.map(toACVMField)];
249
249
  }
250
250
 
251
- async utilityGetPublicKeysAndPartialAddress([address]: ACVMField[]): Promise<ACVMField[][]> {
251
+ async utilityTryGetPublicKeysAndPartialAddress([address]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> {
252
252
  const parsedAddress = AztecAddress.fromField(Fr.fromString(address));
253
- const { publicKeys, partialAddress } =
254
- await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(parsedAddress);
253
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(parsedAddress);
255
254
 
256
- return [[...publicKeys.toFields(), partialAddress].map(toACVMField)];
255
+ // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
256
+ // with two fields: `some` (a boolean) and `value` (a field array in this case).
257
+ if (result === undefined) {
258
+ // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
259
+ return [toACVMField(0), Array(13).fill(toACVMField(0))];
260
+ } else {
261
+ // Data was found so we set `some` to 1 and return it along with `value`.
262
+ return [toACVMField(1), [...result.publicKeys.toFields(), result.partialAddress].map(toACVMField)];
263
+ }
257
264
  }
258
265
 
259
266
  async utilityGetNotes(
@@ -30,7 +30,7 @@ import {
30
30
  type TxContext,
31
31
  } from '@aztec/stdlib/tx';
32
32
 
33
- import { ensureContractSynced } from '../../contract_sync/index.js';
33
+ import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
34
34
  import { NoteService } from '../../notes/note_service.js';
35
35
  import type { AddressStore } from '../../storage/address_store/address_store.js';
36
36
  import type { CapsuleStore } from '../../storage/capsule_store/capsule_store.js';
@@ -93,6 +93,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
93
93
  senderAddressBookStore: SenderAddressBookStore,
94
94
  capsuleStore: CapsuleStore,
95
95
  privateEventStore: PrivateEventStore,
96
+ private readonly contractSyncService: ContractSyncService,
96
97
  jobId: string,
97
98
  private totalPublicCalldataCount: number = 0,
98
99
  protected sideEffectCounter: number = 0,
@@ -242,7 +243,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
242
243
  sender: AztecAddress,
243
244
  recipient: AztecAddress,
244
245
  ) {
245
- const senderCompleteAddress = await this.getCompleteAddress(sender);
246
+ const senderCompleteAddress = await this.getCompleteAddressOrFail(sender);
246
247
  const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
247
248
  return DirectionalAppTaggingSecret.compute(
248
249
  senderCompleteAddress,
@@ -537,13 +538,12 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
537
538
 
538
539
  isStaticCall = isStaticCall || this.callContext.isStaticCall;
539
540
 
540
- await ensureContractSynced(
541
+ await this.contractSyncService.ensureContractSynced(
541
542
  targetContractAddress,
542
543
  functionSelector,
543
544
  this.utilityExecutor,
544
- this.aztecNode,
545
- this.contractStore,
546
545
  this.anchorBlockHeader,
546
+ this.jobId,
547
547
  );
548
548
 
549
549
  const targetArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(
@@ -576,6 +576,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
576
576
  this.senderAddressBookStore,
577
577
  this.capsuleStore,
578
578
  this.privateEventStore,
579
+ this.contractSyncService,
579
580
  this.jobId,
580
581
  this.totalPublicCalldataCount,
581
582
  sideEffectCounter,
@@ -88,8 +88,16 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
88
88
  * @param pkMHash - The master public key hash.
89
89
  * @returns A Promise that resolves to nullifier keys.
90
90
  * @throws If the keys are not registered in the key store.
91
+ * @throws If scopes are defined and the account is not in the scopes.
91
92
  */
92
- public utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
93
+ public async utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
94
+ // If scopes are defined, check that the key belongs to an account in the scopes
95
+ if (this.scopes && this.scopes.length > 0) {
96
+ const [, account] = await this.keyStore.getKeyPrefixAndAccount(pkMHash);
97
+ if (!this.scopes.some(scope => scope.equals(account))) {
98
+ throw new Error(`Key validation request denied: account ${account.toString()} is not in the allowed scopes.`);
99
+ }
100
+ }
93
101
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
94
102
  }
95
103
 
@@ -182,14 +190,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
182
190
  /**
183
191
  * Retrieve the complete address associated to a given address.
184
192
  * @param account - The account address.
185
- * @returns A complete address associated with the input address.
186
- * @throws An error if the account is not registered in the database.
193
+ * @returns A complete address associated with the input address, or `undefined` if not registered.
187
194
  */
188
- public utilityGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress> {
189
- return this.getCompleteAddress(account);
195
+ public utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress | undefined> {
196
+ return this.addressStore.getCompleteAddress(account);
190
197
  }
191
198
 
192
- protected async getCompleteAddress(account: AztecAddress): Promise<CompleteAddress> {
199
+ protected async getCompleteAddressOrFail(account: AztecAddress): Promise<CompleteAddress> {
193
200
  const completeAddress = await this.addressStore.getCompleteAddress(account);
194
201
  if (!completeAddress) {
195
202
  throw new Error(
@@ -290,8 +297,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
290
297
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
291
298
  */
292
299
  public async utilityCheckNullifierExists(innerNullifier: Fr) {
293
- const nullifier = await siloNullifier(this.contractAddress, innerNullifier!);
294
- const [leafIndex] = await this.aztecNode.findLeavesIndexes('latest', MerkleTreeId.NULLIFIER_TREE, [nullifier]);
300
+ const [nullifier, anchorBlockHash] = await Promise.all([
301
+ siloNullifier(this.contractAddress, innerNullifier!),
302
+ this.anchorBlockHeader.hash(),
303
+ ]);
304
+ const [leafIndex] = await this.aztecNode.findLeavesIndexes(anchorBlockHash, MerkleTreeId.NULLIFIER_TREE, [
305
+ nullifier,
306
+ ]);
295
307
  return leafIndex?.data !== undefined;
296
308
  }
297
309
 
@@ -363,16 +375,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
363
375
  this.log.getBindings(),
364
376
  );
365
377
 
366
- const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
367
-
368
- // It is acceptable to run the following operations in parallel for several reasons:
369
- // 1. syncTaggedLogs does not write to the note store — it only stores the pending tagged logs in a capsule array,
370
- // which is then processed in Noir after this handler returns.
371
- // 2. Even if syncTaggedLogs did write to the note store, it would not cause inconsistent state.
372
- await Promise.all([
373
- logService.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes),
374
- noteService.syncNoteNullifiers(this.contractAddress),
375
- ]);
378
+ await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
376
379
  }
377
380
 
378
381
  /**
@@ -544,7 +547,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
544
547
 
545
548
  protected async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
546
549
  // TODO(#12656): return an app-siloed secret
547
- const recipientCompleteAddress = await this.getCompleteAddress(address);
550
+ const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
548
551
  const ivskM = await this.keyStore.getMasterSecretKey(
549
552
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
550
553
  );
@@ -0,0 +1,129 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+ import type { FunctionCall, FunctionSelector } from '@aztec/stdlib/abi';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
+ import type { BlockHeader } from '@aztec/stdlib/tx';
6
+
7
+ import type { StagedStore } from '../job_coordinator/job_coordinator.js';
8
+ import type { ContractStore } from '../storage/contract_store/contract_store.js';
9
+ import type { NoteStore } from '../storage/note_store/note_store.js';
10
+ import { syncState, verifyCurrentClassId } from './helpers.js';
11
+
12
+ /**
13
+ * Service for syncing the private state of contracts and verifying that the PXE holds the current class artifact.
14
+ * It uses a cache to avoid redundant sync operations - the cache is wiped when the anchor block changes.
15
+ *
16
+ * TODO: The StagedStore naming is broken here. Figure out a better name.
17
+ */
18
+ export class ContractSyncService implements StagedStore {
19
+ readonly storeName = 'contract_sync';
20
+
21
+ // Tracks contracts synced since last wipe. Key is contract address string, value is a promise that resolves when
22
+ // the contract is synced.
23
+ private syncedContracts: Map<string, Promise<void>> = new Map();
24
+
25
+ // Per-job overridden contract addresses - these contracts should not be synced.
26
+ private overriddenContracts: Map<string, Set<string>> = new Map();
27
+
28
+ constructor(
29
+ private aztecNode: AztecNode,
30
+ private contractStore: ContractStore,
31
+ private noteStore: NoteStore,
32
+ private log: Logger,
33
+ ) {}
34
+
35
+ /** Sets contracts that should be skipped during sync for a specific job. */
36
+ setOverriddenContracts(jobId: string, addresses: Set<string>): void {
37
+ this.overriddenContracts.set(jobId, addresses);
38
+ }
39
+
40
+ /**
41
+ * Ensures a contract's private state is synchronized and that the PXE holds the current class artifact.
42
+ * Uses a cache to avoid redundant sync operations - the cache is wiped when the anchor block changes.
43
+ * @param contractAddress - The address of the contract to sync.
44
+ * @param functionToInvokeAfterSync - The function selector that will be called after sync (used to validate it's
45
+ * not sync_state itself).
46
+ * @param utilityExecutor - Executor function for running the sync_state utility function.
47
+ */
48
+ async ensureContractSynced(
49
+ contractAddress: AztecAddress,
50
+ functionToInvokeAfterSync: FunctionSelector | null,
51
+ utilityExecutor: (call: FunctionCall) => Promise<any>,
52
+ anchorBlockHeader: BlockHeader,
53
+ jobId: string,
54
+ ): Promise<void> {
55
+ const key = contractAddress.toString();
56
+
57
+ // Skip sync if this contract has an override for this job
58
+ const overrides = this.overriddenContracts.get(jobId);
59
+ if (overrides?.has(key)) {
60
+ return;
61
+ }
62
+
63
+ const existing = this.syncedContracts.get(key);
64
+ if (existing) {
65
+ return existing;
66
+ }
67
+
68
+ const syncPromise = this.#doSync(
69
+ contractAddress,
70
+ functionToInvokeAfterSync,
71
+ utilityExecutor,
72
+ anchorBlockHeader,
73
+ jobId,
74
+ );
75
+ this.syncedContracts.set(key, syncPromise);
76
+
77
+ try {
78
+ await syncPromise;
79
+ } catch (err) {
80
+ // There was an error syncing the contract, so we remove it from the cache so that it can be retried.
81
+ this.syncedContracts.delete(key);
82
+ throw err;
83
+ }
84
+ }
85
+
86
+ async #doSync(
87
+ contractAddress: AztecAddress,
88
+ functionToInvokeAfterSync: FunctionSelector | null,
89
+ utilityExecutor: (call: FunctionCall) => Promise<any>,
90
+ anchorBlockHeader: BlockHeader,
91
+ jobId: string,
92
+ ): Promise<void> {
93
+ this.log.debug(`Syncing contract ${contractAddress}`);
94
+ await Promise.all([
95
+ syncState(
96
+ contractAddress,
97
+ this.contractStore,
98
+ functionToInvokeAfterSync,
99
+ utilityExecutor,
100
+ this.noteStore,
101
+ this.aztecNode,
102
+ anchorBlockHeader,
103
+ jobId,
104
+ ),
105
+ verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
106
+ ]);
107
+ this.log.debug(`Contract ${contractAddress} synced`);
108
+ }
109
+
110
+ /** Clears sync cache. Called by BlockSynchronizer when anchor block changes. */
111
+ wipe(): void {
112
+ this.log.debug(`Wiping contract sync cache (${this.syncedContracts.size} entries)`);
113
+ this.syncedContracts.clear();
114
+ }
115
+
116
+ commit(jobId: string): Promise<void> {
117
+ // Clear overridden contracts for this job
118
+ this.overriddenContracts.delete(jobId);
119
+ return Promise.resolve();
120
+ }
121
+
122
+ discardStaged(jobId: string): Promise<void> {
123
+ // We clear the synced contracts cache here because, when the job is discarded, any associated database writes from
124
+ // the sync are also undone.
125
+ this.syncedContracts.clear();
126
+ this.overriddenContracts.delete(jobId);
127
+ return Promise.resolve();
128
+ }
129
+ }
@@ -6,7 +6,9 @@ import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '
6
6
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
7
7
  import type { BlockHeader } from '@aztec/stdlib/tx';
8
8
 
9
+ import { NoteService } from '../notes/note_service.js';
9
10
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
11
+ import type { NoteStore } from '../storage/note_store/note_store.js';
10
12
 
11
13
  /**
12
14
  * Read the current class id of a contract from the execution data provider or AztecNode. If not found, class id
@@ -41,6 +43,10 @@ export async function syncState(
41
43
  contractStore: ContractStore,
42
44
  functionToInvokeAfterSync: FunctionSelector | null,
43
45
  utilityExecutor: (privateSyncCall: FunctionCall) => Promise<any>,
46
+ noteStore: NoteStore,
47
+ aztecNode: AztecNode,
48
+ anchorBlockHeader: BlockHeader,
49
+ jobId: string,
44
50
  ) {
45
51
  // Protocol contracts don't have private state to sync
46
52
  if (!isProtocolContract(contractAddress)) {
@@ -51,16 +57,23 @@ export async function syncState(
51
57
  );
52
58
  }
53
59
 
54
- return utilityExecutor(syncStateFunctionCall);
60
+ const noteService = new NoteService(noteStore, aztecNode, anchorBlockHeader, jobId);
61
+
62
+ // Both sync_state and syncNoteNullifiers interact with the note store, but running them in parallel is safe
63
+ // because note store is designed to handle concurrent operations.
64
+ await Promise.all([utilityExecutor(syncStateFunctionCall), noteService.syncNoteNullifiers(contractAddress)]);
55
65
  }
56
66
  }
57
67
 
58
68
  /**
59
69
  * Verify that the current class id of a contract obtained from AztecNode is the same as the one in contract data
60
70
  * provider (i.e. PXE's own storage).
71
+ * @param contractAddress - The address of the contract to verify.
72
+ * @param aztecNode - The Aztec node to query for storage.
73
+ * @param contractStore - The contract store to fetch the local instance from.
61
74
  * @param header - The header of the block at which to verify the current class id.
62
75
  */
63
- async function verifyCurrentClassId(
76
+ export async function verifyCurrentClassId(
64
77
  contractAddress: AztecAddress,
65
78
  aztecNode: AztecNode,
66
79
  contractStore: ContractStore,
@@ -78,21 +91,3 @@ async function verifyCurrentClassId(
78
91
  );
79
92
  }
80
93
  }
81
-
82
- /**
83
- * Ensures the contract's private state is synchronized and that the PXE holds the current class artifact for
84
- * the contract.
85
- */
86
- export async function ensureContractSynced(
87
- contractAddress: AztecAddress,
88
- functionToInvokeAfterSync: FunctionSelector | null,
89
- utilityExecutor: (call: FunctionCall) => Promise<any>,
90
- aztecNode: AztecNode,
91
- contractStore: ContractStore,
92
- header: BlockHeader,
93
- ): Promise<void> {
94
- await Promise.all([
95
- syncState(contractAddress, contractStore, functionToInvokeAfterSync, utilityExecutor),
96
- verifyCurrentClassId(contractAddress, aztecNode, contractStore, header),
97
- ]);
98
- }