@aztec/pxe 0.0.1-commit.f650c0a5c → 0.0.1-commit.f7ea82942

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 (77) hide show
  1. package/dest/block_synchronizer/block_synchronizer.d.ts +6 -2
  2. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.js +13 -1
  4. package/dest/config/index.d.ts +1 -1
  5. package/dest/config/index.d.ts.map +1 -1
  6. package/dest/config/index.js +7 -14
  7. package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -1
  8. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/contract_function_simulator.js +6 -4
  10. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +3 -2
  11. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +11 -5
  13. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +6 -5
  14. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +5 -4
  16. package/dest/contract_function_simulator/pick_notes.d.ts +1 -1
  17. package/dest/contract_function_simulator/pick_notes.d.ts.map +1 -1
  18. package/dest/contract_function_simulator/pick_notes.js +11 -1
  19. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts +1 -1
  20. package/dest/contract_function_simulator/proxied_contract_data_source.d.ts.map +1 -1
  21. package/dest/contract_function_simulator/proxied_contract_data_source.js +3 -0
  22. package/dest/contract_sync/contract_sync_service.d.ts +1 -1
  23. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  24. package/dest/contract_sync/contract_sync_service.js +35 -23
  25. package/dest/events/event_service.d.ts +1 -1
  26. package/dest/events/event_service.d.ts.map +1 -1
  27. package/dest/events/event_service.js +10 -1
  28. package/dest/events/private_event_filter_validator.d.ts +3 -2
  29. package/dest/events/private_event_filter_validator.d.ts.map +1 -1
  30. package/dest/events/private_event_filter_validator.js +15 -0
  31. package/dest/logs/log_service.d.ts +4 -2
  32. package/dest/logs/log_service.d.ts.map +1 -1
  33. package/dest/logs/log_service.js +6 -3
  34. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  35. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  36. package/dest/private_kernel/private_kernel_execution_prover.js +4 -7
  37. package/dest/private_kernel/private_kernel_oracle.d.ts +5 -5
  38. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  39. package/dest/private_kernel/private_kernel_oracle.js +12 -15
  40. package/dest/pxe.d.ts +2 -1
  41. package/dest/pxe.d.ts.map +1 -1
  42. package/dest/pxe.js +23 -16
  43. package/dest/storage/anchor_block_store/anchor_block_store.js +1 -1
  44. package/dest/storage/capsule_store/capsule_store.d.ts +1 -1
  45. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  46. package/dest/storage/capsule_store/capsule_store.js +8 -5
  47. package/dest/storage/contract_store/contract_store.d.ts +1 -1
  48. package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
  49. package/dest/storage/contract_store/contract_store.js +4 -2
  50. package/dest/storage/private_event_store/private_event_store.d.ts +1 -1
  51. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  52. package/dest/storage/private_event_store/private_event_store.js +3 -0
  53. package/dest/storage/private_event_store/stored_private_event.js +1 -1
  54. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +2 -2
  55. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  56. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +2 -16
  57. package/package.json +16 -16
  58. package/src/block_synchronizer/block_synchronizer.ts +16 -2
  59. package/src/config/index.ts +2 -8
  60. package/src/contract_function_simulator/contract_function_simulator.ts +7 -4
  61. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +17 -4
  62. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +7 -4
  63. package/src/contract_function_simulator/pick_notes.ts +13 -1
  64. package/src/contract_function_simulator/proxied_contract_data_source.ts +8 -1
  65. package/src/contract_sync/contract_sync_service.ts +57 -51
  66. package/src/events/event_service.ts +13 -1
  67. package/src/events/private_event_filter_validator.ts +21 -1
  68. package/src/logs/log_service.ts +6 -1
  69. package/src/private_kernel/private_kernel_execution_prover.ts +4 -9
  70. package/src/private_kernel/private_kernel_oracle.ts +14 -14
  71. package/src/pxe.ts +53 -16
  72. package/src/storage/anchor_block_store/anchor_block_store.ts +1 -1
  73. package/src/storage/capsule_store/capsule_store.ts +15 -5
  74. package/src/storage/contract_store/contract_store.ts +8 -6
  75. package/src/storage/private_event_store/private_event_store.ts +4 -0
  76. package/src/storage/private_event_store/stored_private_event.ts +1 -1
  77. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +5 -15
package/src/pxe.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  } from '@aztec/stdlib/abi';
19
19
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
20
20
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
21
+ import type { L2TipsProvider } from '@aztec/stdlib/block';
21
22
  import {
22
23
  CompleteAddress,
23
24
  type ContractInstanceWithAddress,
@@ -161,6 +162,7 @@ export class PXE {
161
162
  private privateEventStore: PrivateEventStore,
162
163
  private contractSyncService: ContractSyncService,
163
164
  private messageContextService: MessageContextService,
165
+ private l2TipsStore: L2TipsProvider,
164
166
  private simulator: CircuitSimulator,
165
167
  private proverEnabled: boolean,
166
168
  private proofCreator: PrivateKernelProver,
@@ -260,6 +262,7 @@ export class PXE {
260
262
  privateEventStore,
261
263
  contractSyncService,
262
264
  messageContextService,
265
+ tipsStore,
263
266
  simulator,
264
267
  proverEnabled,
265
268
  proofCreator,
@@ -294,6 +297,7 @@ export class PXE {
294
297
  keyStore: this.keyStore,
295
298
  addressStore: this.addressStore,
296
299
  aztecNode: BenchmarkedNodeFactory.create(this.node),
300
+ l2TipsStore: this.l2TipsStore,
297
301
  senderTaggingStore: this.senderTaggingStore,
298
302
  recipientTaggingStore: this.recipientTaggingStore,
299
303
  senderAddressBookStore: this.senderAddressBookStore,
@@ -367,14 +371,13 @@ export class PXE {
367
371
  async #executePrivate(
368
372
  contractFunctionSimulator: ContractFunctionSimulator,
369
373
  txRequest: TxExecutionRequest,
374
+ anchorBlockHeader: BlockHeader,
370
375
  scopes: AztecAddress[],
371
376
  jobId: string,
372
377
  ): Promise<PrivateExecutionResult> {
373
378
  const { origin: contractAddress, functionSelector } = txRequest;
374
379
 
375
380
  try {
376
- const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
377
-
378
381
  await this.contractSyncService.ensureContractSynced(
379
382
  contractAddress,
380
383
  functionSelector,
@@ -479,11 +482,10 @@ export class PXE {
479
482
  txExecutionRequest: TxExecutionRequest,
480
483
  proofCreator: PrivateKernelProver,
481
484
  privateExecutionResult: PrivateExecutionResult,
485
+ anchorBlockHeader: BlockHeader,
482
486
  config: PrivateKernelExecutionProverConfig,
483
487
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
484
- const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
485
- const anchorBlockHash = await anchorBlockHeader.hash();
486
- const kernelOracle = new PrivateKernelOracle(this.contractStore, this.keyStore, this.node, anchorBlockHash);
488
+ const kernelOracle = new PrivateKernelOracle(this.contractStore, this.keyStore, this.node, anchorBlockHeader);
487
489
  const kernelTraceProver = new PrivateKernelExecutionProver(
488
490
  kernelOracle,
489
491
  proofCreator,
@@ -560,6 +562,12 @@ export class PXE {
560
562
  * TODO: It's strange that we return the address here and I (benesjan) think we should drop the return value.
561
563
  */
562
564
  public async registerSender(sender: AztecAddress): Promise<AztecAddress> {
565
+ if (!(await sender.isValid())) {
566
+ throw new Error(
567
+ `Address ${sender} is not valid: it does not correspond to a point on the Grumpkin curve. Cannot register it as a sender.`,
568
+ );
569
+ }
570
+
563
571
  const accounts = await this.keyStore.getAccounts();
564
572
  if (accounts.includes(sender)) {
565
573
  this.log.info(`Sender:\n "${sender.toString()}"\n already registered.`);
@@ -571,8 +579,8 @@ export class PXE {
571
579
  if (wasAdded) {
572
580
  this.log.info(`Added sender:\n ${sender.toString()}`);
573
581
  // Wipe the entire sync cache: the new sender's tagged logs could contain notes/events for any contract, so
574
- // all contracts must re-sync to discover them.
575
- this.contractSyncService.wipe();
582
+ // all contracts must re-sync to discover them. Queued to avoid wiping while a job is in flight.
583
+ await this.#putInJobQueue(() => Promise.resolve(this.contractSyncService.wipe()));
576
584
  } else {
577
585
  this.log.info(`Sender:\n "${sender.toString()}"\n already registered.`);
578
586
  }
@@ -741,16 +749,23 @@ export class PXE {
741
749
  try {
742
750
  const syncTimer = new Timer();
743
751
  await this.blockStateSynchronizer.sync();
752
+ const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
744
753
  const syncTime = syncTimer.ms();
745
754
  const contractFunctionSimulator = this.#getSimulatorForTx();
746
- privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
755
+ privateExecutionResult = await this.#executePrivate(
756
+ contractFunctionSimulator,
757
+ txRequest,
758
+ anchorBlockHeader,
759
+ scopes,
760
+ jobId,
761
+ );
747
762
 
748
763
  const {
749
764
  publicInputs,
750
765
  chonkProof,
751
766
  executionSteps,
752
767
  timings: { proving } = {},
753
- } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
768
+ } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, anchorBlockHeader, {
754
769
  simulate: false,
755
770
  skipFeeEnforcement: false,
756
771
  profileMode: 'none',
@@ -833,15 +848,23 @@ export class PXE {
833
848
  );
834
849
  const syncTimer = new Timer();
835
850
  await this.blockStateSynchronizer.sync();
851
+ const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
836
852
  const syncTime = syncTimer.ms();
837
853
 
838
854
  const contractFunctionSimulator = this.#getSimulatorForTx();
839
- const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
855
+ const privateExecutionResult = await this.#executePrivate(
856
+ contractFunctionSimulator,
857
+ txRequest,
858
+ anchorBlockHeader,
859
+ scopes,
860
+ jobId,
861
+ );
840
862
 
841
863
  const { executionSteps, timings: { proving } = {} } = await this.#prove(
842
864
  txRequest,
843
865
  this.proofCreator,
844
866
  privateExecutionResult,
867
+ anchorBlockHeader,
845
868
  {
846
869
  simulate: skipProofGeneration,
847
870
  skipFeeEnforcement: false,
@@ -931,6 +954,7 @@ export class PXE {
931
954
  );
932
955
  const syncTimer = new Timer();
933
956
  await this.blockStateSynchronizer.sync();
957
+ const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
934
958
  const syncTime = syncTimer.ms();
935
959
 
936
960
  const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined;
@@ -950,7 +974,13 @@ export class PXE {
950
974
  }
951
975
 
952
976
  // Execution of private functions only; no proving, and no kernel logic.
953
- const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
977
+ const privateExecutionResult = await this.#executePrivate(
978
+ contractFunctionSimulator,
979
+ txRequest,
980
+ anchorBlockHeader,
981
+ scopes,
982
+ jobId,
983
+ );
954
984
 
955
985
  let publicInputs: PrivateKernelTailCircuitPublicInputs | undefined;
956
986
  let executionSteps: PrivateExecutionStep[] = [];
@@ -963,11 +993,17 @@ export class PXE {
963
993
  ));
964
994
  } else {
965
995
  // Kernel logic, plus proving of all private functions and kernels.
966
- ({ publicInputs, executionSteps } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
967
- simulate: true,
968
- skipFeeEnforcement,
969
- profileMode: 'none',
970
- }));
996
+ ({ publicInputs, executionSteps } = await this.#prove(
997
+ txRequest,
998
+ this.proofCreator,
999
+ privateExecutionResult,
1000
+ anchorBlockHeader,
1001
+ {
1002
+ simulate: true,
1003
+ skipFeeEnforcement,
1004
+ profileMode: 'none',
1005
+ },
1006
+ ));
971
1007
  }
972
1008
 
973
1009
  const privateSimulationResult = new PrivateSimulationResult(privateExecutionResult, publicInputs);
@@ -1170,6 +1206,7 @@ export class PXE {
1170
1206
  */
1171
1207
  public async stop(): Promise<void> {
1172
1208
  await this.jobQueue.end();
1209
+ await this.blockStateSynchronizer.stop();
1173
1210
  await this.db.close();
1174
1211
  }
1175
1212
  }
@@ -23,7 +23,7 @@ export class AnchorBlockStore {
23
23
  }
24
24
 
25
25
  async getBlockHeader(): Promise<BlockHeader> {
26
- const headerBuffer = await this.#synchronizedHeader.getAsync();
26
+ const headerBuffer = await this.#store.transactionAsync(() => this.#synchronizedHeader.getAsync());
27
27
  if (!headerBuffer) {
28
28
  throw new Error(`Trying to get block header with a not-yet-synchronized PXE - this should never happen`);
29
29
  }
@@ -148,7 +148,17 @@ export class CapsuleStore implements StagedStore {
148
148
  * @param slot - The slot in the database to read.
149
149
  * @returns The stored data or `null` if no data is stored under the slot.
150
150
  */
151
- async getCapsule(contractAddress: AztecAddress, slot: Fr, jobId: string, scope: AztecAddress): Promise<Fr[] | null> {
151
+ getCapsule(contractAddress: AztecAddress, slot: Fr, jobId: string, scope: AztecAddress): Promise<Fr[] | null> {
152
+ return this.#store.transactionAsync(() => this.#getCapsuleInternal(contractAddress, slot, jobId, scope));
153
+ }
154
+
155
+ /** Same as getCapsule but without its own transaction, for use inside an existing transactionAsync. */
156
+ async #getCapsuleInternal(
157
+ contractAddress: AztecAddress,
158
+ slot: Fr,
159
+ jobId: string,
160
+ scope: AztecAddress,
161
+ ): Promise<Fr[] | null> {
152
162
  const dataBuffer = await this.#getFromStage(jobId, dbSlotToKey(contractAddress, slot, scope));
153
163
  if (!dataBuffer) {
154
164
  this.logger.trace(`Data not found for contract ${contractAddress.toString()} and slot ${slot.toString()}`);
@@ -240,7 +250,7 @@ export class CapsuleStore implements StagedStore {
240
250
  // and not using a transaction here would heavily impact performance.
241
251
  return this.#store.transactionAsync(async () => {
242
252
  // Load current length, defaulting to 0 if not found
243
- const lengthData = await this.getCapsule(contractAddress, baseSlot, jobId, scope);
253
+ const lengthData = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope);
244
254
  const currentLength = lengthData ? lengthData[0].toNumber() : 0;
245
255
 
246
256
  // Store each capsule at consecutive slots after baseSlot + 1 + currentLength
@@ -263,14 +273,14 @@ export class CapsuleStore implements StagedStore {
263
273
  // of jobs: different calls running concurrently on the same contract may cause trouble.
264
274
  return this.#store.transactionAsync(async () => {
265
275
  // Load length, defaulting to 0 if not found
266
- const maybeLength = await this.getCapsule(contractAddress, baseSlot, jobId, scope);
276
+ const maybeLength = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope);
267
277
  const length = maybeLength ? maybeLength[0].toBigInt() : 0n;
268
278
 
269
279
  const values: Fr[][] = [];
270
280
 
271
281
  // Read each capsule at consecutive slots after baseSlot
272
282
  for (let i = 0; i < length; i++) {
273
- const currentValue = await this.getCapsule(contractAddress, arraySlot(baseSlot, i), jobId, scope);
283
+ const currentValue = await this.#getCapsuleInternal(contractAddress, arraySlot(baseSlot, i), jobId, scope);
274
284
  if (currentValue == undefined) {
275
285
  throw new Error(
276
286
  `Expected non-empty value at capsule array in base slot ${baseSlot} at index ${i} for contract ${contractAddress}`,
@@ -295,7 +305,7 @@ export class CapsuleStore implements StagedStore {
295
305
  // of jobs: different calls running concurrently on the same contract may cause trouble.
296
306
  return this.#store.transactionAsync(async () => {
297
307
  // Load current length, defaulting to 0 if not found
298
- const maybeLength = await this.getCapsule(contractAddress, baseSlot, jobId, scope);
308
+ const maybeLength = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope);
299
309
  const originalLength = maybeLength ? maybeLength[0].toNumber() : 0;
300
310
 
301
311
  // Set the new length
@@ -168,12 +168,14 @@ export class ContractStore {
168
168
  }
169
169
 
170
170
  async addContractInstance(contract: ContractInstanceWithAddress): Promise<void> {
171
- this.#contractClassIdMap.set(contract.address.toString(), contract.currentContractClassId);
171
+ await this.#store.transactionAsync(async () => {
172
+ await this.#contractInstances.set(
173
+ contract.address.toString(),
174
+ new SerializableContractInstance(contract).toBuffer(),
175
+ );
176
+ });
172
177
 
173
- await this.#contractInstances.set(
174
- contract.address.toString(),
175
- new SerializableContractInstance(contract).toBuffer(),
176
- );
178
+ this.#contractClassIdMap.set(contract.address.toString(), contract.currentContractClassId);
177
179
  }
178
180
 
179
181
  // Private getters
@@ -246,7 +248,7 @@ export class ContractStore {
246
248
  contractClassId: Fr,
247
249
  ): Promise<(ContractClassWithId & ContractClassIdPreimage) | undefined> {
248
250
  const key = contractClassId.toString();
249
- const buf = await this.#contractClassData.getAsync(key);
251
+ const buf = await this.#store.transactionAsync(() => this.#contractClassData.getAsync(key));
250
252
  if (!buf) {
251
253
  return undefined;
252
254
  }
@@ -234,6 +234,10 @@ export class PrivateEventStore implements StagedStore {
234
234
  * IMPORTANT: This method must be called within a transaction to ensure atomicity.
235
235
  */
236
236
  public async rollback(blockNumber: number, synchedBlockNumber: number): Promise<void> {
237
+ if (this.#eventsForJob.size > 0) {
238
+ throw new Error('PXE private event store rollback is not allowed while jobs are running');
239
+ }
240
+
237
241
  // First pass: collect all event IDs for all blocks, starting reads during iteration to keep tx alive.
238
242
  const eventsByBlock: Map<number, { eventId: string; eventReadPromise: Promise<Buffer | undefined> }[]> = new Map();
239
243
 
@@ -49,7 +49,7 @@ export class StoredPrivateEvent {
49
49
  const msgContentLength = reader.readNumber();
50
50
  const msgContent = reader.readArray(msgContentLength, Fr);
51
51
  const l2BlockNumber = reader.readNumber();
52
- const l2BlockHash = new BlockHash(Fr.fromBuffer(reader));
52
+ const l2BlockHash = BlockHash.fromBuffer(reader);
53
53
  const txHash = TxHash.fromBuffer(reader);
54
54
  const txIndexInBlock = reader.readNumber();
55
55
  const eventIndexInTx = reader.readNumber();
@@ -21,6 +21,8 @@ export async function loadPrivateLogsForSenderRecipientPair(
21
21
  taggingStore: RecipientTaggingStore,
22
22
  anchorBlockNumber: BlockNumber,
23
23
  anchorBlockHash: BlockHash,
24
+ currentTimestamp: bigint,
25
+ finalizedBlockNumber: BlockNumber,
24
26
  jobId: string,
25
27
  ): Promise<TxScopedL2Log[]> {
26
28
  // # Explanation of how the algorithm works
@@ -61,20 +63,6 @@ export async function loadPrivateLogsForSenderRecipientPair(
61
63
  // the highest finalized index. If that index was already used, they will throw an error. For this reason we
62
64
  // don't have to look further than `highestFinalizedIndex + WINDOW_LEN`.
63
65
 
64
- let finalizedBlockNumber: number, currentTimestamp: bigint;
65
- {
66
- const [l2Tips, latestBlockHeader] = await Promise.all([aztecNode.getL2Tips(), aztecNode.getBlockHeader('latest')]);
67
-
68
- if (!latestBlockHeader) {
69
- throw new Error('Node failed to return latest block header when syncing logs');
70
- }
71
-
72
- [finalizedBlockNumber, currentTimestamp] = [
73
- l2Tips.finalized.block.number,
74
- latestBlockHeader.globalVariables.timestamp,
75
- ];
76
- }
77
-
78
66
  let start: number, end: number;
79
67
  {
80
68
  const currentHighestAgedIndex = await taggingStore.getHighestAgedIndex(secret, jobId);
@@ -125,7 +113,9 @@ export async function loadPrivateLogsForSenderRecipientPair(
125
113
 
126
114
  if (highestAgedIndex !== undefined && highestAgedIndex > highestFinalizedIndex) {
127
115
  // This is just a sanity check as this should never happen.
128
- throw new Error('Highest aged index lower than highest finalized index invariant violated');
116
+ throw new Error(
117
+ `Highest aged index (${highestAgedIndex}) must not exceed highest finalized index (${highestFinalizedIndex})`,
118
+ );
129
119
  }
130
120
 
131
121
  await taggingStore.updateHighestFinalizedIndex(secret, highestFinalizedIndex, jobId);