@aztec/pxe 0.0.1-commit.f1df4d2 → 0.0.1-commit.f2ce05ee

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 (52) 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 +5 -3
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/contract_function_simulator.js +6 -4
  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 +1 -1
  10. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  11. package/dest/contract_function_simulator/oracle/oracle.js +3 -3
  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 +5 -5
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +8 -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 +33 -7
  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} +6 -12
  24. package/dest/debug/pxe_debug_utils.d.ts +12 -9
  25. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  26. package/dest/debug/pxe_debug_utils.js +16 -15
  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/pxe.d.ts +13 -2
  31. package/dest/pxe.d.ts.map +1 -1
  32. package/dest/pxe.js +35 -14
  33. package/dest/storage/contract_store/contract_store.js +5 -5
  34. package/dest/storage/note_store/note_store.d.ts +1 -1
  35. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  36. package/dest/storage/note_store/note_store.js +3 -0
  37. package/package.json +25 -16
  38. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  39. package/src/contract_function_simulator/contract_function_simulator.ts +5 -2
  40. package/src/contract_function_simulator/oracle/interfaces.ts +1 -1
  41. package/src/contract_function_simulator/oracle/oracle.ts +3 -3
  42. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +4 -5
  43. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +36 -7
  44. package/src/contract_sync/contract_sync_service.ts +129 -0
  45. package/src/contract_sync/{index.ts → helpers.ts} +6 -32
  46. package/src/debug/pxe_debug_utils.ts +45 -17
  47. package/src/entrypoints/server/index.ts +1 -1
  48. package/src/pxe.ts +45 -17
  49. package/src/storage/contract_store/contract_store.ts +4 -4
  50. package/src/storage/note_store/note_store.ts +4 -0
  51. package/dest/contract_sync/index.d.ts +0 -24
  52. 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, this.noteStore, anchorBlockHeader, jobId);
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);
@@ -252,7 +257,17 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
252
257
  return await kernelTraceProver.proveWithKernels(txExecutionRequest.toTxRequest(), privateExecutionResult, config);
253
258
  }
254
259
  // Public API
255
- getContractInstance(address) {
260
+ /**
261
+ * Returns the block header up to which the PXE has synced.
262
+ * @returns The synced block header
263
+ */ getSyncedBlockHeader() {
264
+ return this.anchorBlockStore.getBlockHeader();
265
+ }
266
+ /**
267
+ * Returns the contract instance for a given address, if it's registered in the PXE.
268
+ * @param address - The contract address.
269
+ * @returns The contract instance if found, undefined otherwise.
270
+ */ getContractInstance(address) {
256
271
  return this.contractStore.getContractInstance(address);
257
272
  }
258
273
  /**
@@ -586,13 +601,19 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
586
601
  // Temporary: in case there are overrides, we have to skip the kernels or validations
587
602
  // will fail. Consider handing control to the user/wallet on whether they want to run them
588
603
  // or not.
589
- const skipKernels = overrides?.contracts !== undefined && Object.keys(overrides.contracts ?? {}).length > 0;
604
+ const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined;
605
+ const hasOverriddenContracts = overriddenContracts !== undefined && overriddenContracts.size > 0;
606
+ const skipKernels = hasOverriddenContracts;
607
+ // Set overridden contracts on the sync service so it knows to skip syncing them
608
+ if (hasOverriddenContracts) {
609
+ this.contractSyncService.setOverriddenContracts(jobId, overriddenContracts);
610
+ }
590
611
  // Execution of private functions only; no proving, and no kernel logic.
591
612
  const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
592
613
  let publicInputs;
593
614
  let executionSteps = [];
594
615
  if (skipKernels) {
595
- ({ publicInputs, executionSteps } = await generateSimulatedProvingResult(privateExecutionResult, this.contractStore));
616
+ ({ publicInputs, executionSteps } = await generateSimulatedProvingResult(privateExecutionResult, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel)));
596
617
  } else {
597
618
  // Kernel logic, plus proving of all private functions and kernels.
598
619
  ({ publicInputs, executionSteps } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
@@ -677,7 +698,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
677
698
  const functionTimer = new Timer();
678
699
  const contractFunctionSimulator = this.#getSimulatorForTx();
679
700
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
680
- await ensureContractSynced(call.to, call.selector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), this.node, this.contractStore, this.noteStore, anchorBlockHeader, jobId);
701
+ await this.contractSyncService.ensureContractSynced(call.to, call.selector, (privateSyncCall)=>this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), anchorBlockHeader, jobId);
681
702
  const executionResult = await this.#simulateUtility(contractFunctionSimulator, call, authwits ?? [], scopes, jobId);
682
703
  const functionTime = functionTimer.ms();
683
704
  const totalTime = totalTimer.ms();
@@ -727,7 +748,7 @@ import { SenderTaggingStore } from './storage/tagging_store/sender_tagging_store
727
748
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
728
749
  anchorBlockNumber = anchorBlockHeader.getBlockNumber();
729
750
  const contractFunctionSimulator = this.#getSimulatorForTx();
730
- await ensureContractSynced(filter.contractAddress, null, async (privateSyncCall)=>await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), this.node, this.contractStore, this.noteStore, anchorBlockHeader, jobId);
751
+ await this.contractSyncService.ensureContractSynced(filter.contractAddress, null, async (privateSyncCall)=>await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId), anchorBlockHeader, jobId);
731
752
  });
732
753
  // anchorBlockNumber is set during the job and fixed to whatever it is after a block sync
733
754
  const sanitizedFilter = new PrivateEventFilterValidator(anchorBlockNumber).validate(filter);
@@ -1,5 +1,5 @@
1
1
  import { toArray } from '@aztec/foundation/iterable';
2
- import { FunctionSelector, FunctionType, contractArtifactFromBuffer, contractArtifactToBuffer, encodeArguments, getFunctionDebugMetadata } from '@aztec/stdlib/abi';
2
+ import { FunctionCall, FunctionSelector, FunctionType, contractArtifactFromBuffer, contractArtifactToBuffer, encodeArguments, getFunctionDebugMetadata } from '@aztec/stdlib/abi';
3
3
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import { SerializableContractInstance, getContractClassFromArtifact } from '@aztec/stdlib/contract';
5
5
  import { PrivateFunctionsTree } from './private_functions_tree.js';
@@ -219,15 +219,15 @@ import { PrivateFunctionsTree } from './private_functions_tree.js';
219
219
  if (!functionDao) {
220
220
  throw new Error(`Unknown function ${functionName} in contract ${contract.name}.`);
221
221
  }
222
- return {
222
+ return FunctionCall.from({
223
223
  name: functionDao.name,
224
- args: encodeArguments(functionDao, args),
224
+ to,
225
225
  selector: await FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
226
226
  type: functionDao.functionType,
227
- to,
228
227
  hideMsgSender: false,
229
228
  isStatic: functionDao.isStatic,
229
+ args: encodeArguments(functionDao, args),
230
230
  returnTypes: functionDao.returnTypes
231
- };
231
+ });
232
232
  }
233
233
  }
@@ -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.f1df4d2",
3
+ "version": "0.0.1-commit.f2ce05ee",
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.f1df4d2",
65
- "@aztec/bb.js": "0.0.1-commit.f1df4d2",
66
- "@aztec/builder": "0.0.1-commit.f1df4d2",
67
- "@aztec/constants": "0.0.1-commit.f1df4d2",
68
- "@aztec/ethereum": "0.0.1-commit.f1df4d2",
69
- "@aztec/foundation": "0.0.1-commit.f1df4d2",
70
- "@aztec/key-store": "0.0.1-commit.f1df4d2",
71
- "@aztec/kv-store": "0.0.1-commit.f1df4d2",
72
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f1df4d2",
73
- "@aztec/noir-types": "0.0.1-commit.f1df4d2",
74
- "@aztec/protocol-contracts": "0.0.1-commit.f1df4d2",
75
- "@aztec/simulator": "0.0.1-commit.f1df4d2",
76
- "@aztec/stdlib": "0.0.1-commit.f1df4d2",
73
+ "@aztec/bb-prover": "0.0.1-commit.f2ce05ee",
74
+ "@aztec/bb.js": "0.0.1-commit.f2ce05ee",
75
+ "@aztec/builder": "0.0.1-commit.f2ce05ee",
76
+ "@aztec/constants": "0.0.1-commit.f2ce05ee",
77
+ "@aztec/ethereum": "0.0.1-commit.f2ce05ee",
78
+ "@aztec/foundation": "0.0.1-commit.f2ce05ee",
79
+ "@aztec/key-store": "0.0.1-commit.f2ce05ee",
80
+ "@aztec/kv-store": "0.0.1-commit.f2ce05ee",
81
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f2ce05ee",
82
+ "@aztec/noir-types": "0.0.1-commit.f2ce05ee",
83
+ "@aztec/protocol-contracts": "0.0.1-commit.f2ce05ee",
84
+ "@aztec/simulator": "0.0.1-commit.f2ce05ee",
85
+ "@aztec/stdlib": "0.0.1-commit.f2ce05ee",
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.f1df4d2",
86
- "@aztec/noir-test-contracts.js": "0.0.1-commit.f1df4d2",
94
+ "@aztec/merkle-tree": "0.0.1-commit.f2ce05ee",
95
+ "@aztec/noir-test-contracts.js": "0.0.1-commit.f2ce05ee",
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,
@@ -356,7 +359,7 @@ class OrderedSideEffect<T> {
356
359
  */
357
360
  export async function generateSimulatedProvingResult(
358
361
  privateExecutionResult: PrivateExecutionResult,
359
- contractStore: ContractStore,
362
+ debugFunctionNameGetter: (contractAddress: AztecAddress, functionSelector: FunctionSelector) => Promise<string>,
360
363
  minRevertibleSideEffectCounterOverride?: number,
361
364
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
362
365
  const siloedNoteHashes: OrderedSideEffect<Fr>[] = [];
@@ -437,7 +440,7 @@ export async function generateSimulatedProvingResult(
437
440
  : execution.publicInputs.publicTeardownCallRequest;
438
441
 
439
442
  executionSteps.push({
440
- functionName: await contractStore.getDebugFunctionName(
443
+ functionName: await debugFunctionNameGetter(
441
444
  execution.publicInputs.callContext.contractAddress,
442
445
  execution.publicInputs.callContext.functionSelector,
443
446
  ),
@@ -54,7 +54,7 @@ export interface IMiscOracle {
54
54
 
55
55
  utilityGetRandomField(): Fr;
56
56
  utilityAssertCompatibleOracleVersion(version: number): void;
57
- utilityDebugLog(level: number, message: string, fields: Fr[]): void;
57
+ utilityDebugLog(level: number, message: string, fields: Fr[]): Promise<void>;
58
58
  }
59
59
 
60
60
  /**
@@ -417,7 +417,7 @@ export class Oracle {
417
417
  return Promise.resolve([]);
418
418
  }
419
419
 
420
- utilityDebugLog(
420
+ async utilityDebugLog(
421
421
  level: ACVMField[],
422
422
  message: ACVMField[],
423
423
  _ignoredFieldsSize: ACVMField[],
@@ -426,8 +426,8 @@ export class Oracle {
426
426
  const levelFr = Fr.fromString(level[0]);
427
427
  const messageStr = message.map(acvmField => String.fromCharCode(Fr.fromString(acvmField).toNumber())).join('');
428
428
  const fieldsFr = fields.map(Fr.fromString);
429
- this.handlerAsMisc().utilityDebugLog(levelFr.toNumber(), messageStr, fieldsFr);
430
- return Promise.resolve([]);
429
+ await this.handlerAsMisc().utilityDebugLog(levelFr.toNumber(), messageStr, fieldsFr);
430
+ return [];
431
431
  }
432
432
 
433
433
  // This function's name is directly hardcoded in `circuit_recorder.ts`. Don't forget to update it there if you
@@ -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,
@@ -537,13 +538,10 @@ 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
- this.noteStore,
547
545
  this.anchorBlockHeader,
548
546
  this.jobId,
549
547
  );
@@ -578,6 +576,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
578
576
  this.senderAddressBookStore,
579
577
  this.capsuleStore,
580
578
  this.privateEventStore,
579
+ this.contractSyncService,
581
580
  this.jobId,
582
581
  this.totalPublicCalldataCount,
583
582
  sideEffectCounter,
@@ -3,7 +3,7 @@ import type { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Aes128 } from '@aztec/foundation/crypto/aes128';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { Point } from '@aztec/foundation/curves/grumpkin';
6
- import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
6
+ import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
7
7
  import type { MembershipWitness } from '@aztec/foundation/trees';
8
8
  import type { KeyStore } from '@aztec/key-store';
9
9
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
@@ -47,7 +47,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
47
47
  isMisc = true as const;
48
48
  isUtility = true as const;
49
49
 
50
- private aztecNrDebugLog = createLogger('aztec-nr:debug_log');
50
+ private contractLogger: Logger | undefined;
51
51
 
52
52
  constructor(
53
53
  protected readonly contractAddress: AztecAddress,
@@ -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
 
@@ -289,8 +297,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
289
297
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
290
298
  */
291
299
  public async utilityCheckNullifierExists(innerNullifier: Fr) {
292
- const nullifier = await siloNullifier(this.contractAddress, innerNullifier!);
293
- 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
+ ]);
294
307
  return leafIndex?.data !== undefined;
295
308
  }
296
309
 
@@ -341,12 +354,28 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
341
354
  return values;
342
355
  }
343
356
 
344
- public utilityDebugLog(level: number, message: string, fields: Fr[]): void {
357
+ /**
358
+ * Returns a per-contract logger whose output is prefixed with `contract_log::<name>(<addrAbbrev>)`.
359
+ */
360
+ async #getContractLogger(): Promise<Logger> {
361
+ if (!this.contractLogger) {
362
+ const addrAbbrev = this.contractAddress.toString().slice(0, 10);
363
+ const name = await this.contractStore.getDebugContractName(this.contractAddress);
364
+ const module = name ? `contract_log::${name}(${addrAbbrev})` : `contract_log::${addrAbbrev}`;
365
+ // Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
366
+ // to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
367
+ this.contractLogger = createLogger(module, { instanceId: this.jobId });
368
+ }
369
+ return this.contractLogger;
370
+ }
371
+
372
+ public async utilityDebugLog(level: number, message: string, fields: Fr[]): Promise<void> {
345
373
  if (!LogLevels[level]) {
346
374
  throw new Error(`Invalid debug log level: ${level}`);
347
375
  }
348
376
  const levelName = LogLevels[level];
349
- this.aztecNrDebugLog[levelName](`${applyStringFormatting(message, fields)}`);
377
+ const logger = await this.#getContractLogger();
378
+ logger[levelName](`${applyStringFormatting(message, fields)}`);
350
379
  }
351
380
 
352
381
  public async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
@@ -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
+ }