@aztec/pxe 0.69.1 → 0.71.0

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 (75) hide show
  1. package/dest/config/index.d.ts.map +1 -1
  2. package/dest/config/index.js +3 -3
  3. package/dest/database/kv_pxe_database.d.ts +6 -0
  4. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  5. package/dest/database/kv_pxe_database.js +48 -3
  6. package/dest/database/note_dao.d.ts +2 -4
  7. package/dest/database/note_dao.d.ts.map +1 -1
  8. package/dest/database/note_dao.js +1 -5
  9. package/dest/database/outgoing_note_dao.d.ts +1 -3
  10. package/dest/database/outgoing_note_dao.d.ts.map +1 -1
  11. package/dest/database/outgoing_note_dao.js +1 -5
  12. package/dest/database/pxe_database.d.ts +33 -0
  13. package/dest/database/pxe_database.d.ts.map +1 -1
  14. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  15. package/dest/database/pxe_database_test_suite.js +121 -1
  16. package/dest/kernel_oracle/index.js +2 -2
  17. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +2 -2
  18. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
  19. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +1 -1
  20. package/dest/kernel_prover/index.d.ts +0 -1
  21. package/dest/kernel_prover/index.d.ts.map +1 -1
  22. package/dest/kernel_prover/index.js +1 -2
  23. package/dest/kernel_prover/kernel_prover.d.ts +8 -2
  24. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  25. package/dest/kernel_prover/kernel_prover.js +42 -18
  26. package/dest/note_decryption_utils/add_public_values_to_payload.js +2 -2
  27. package/dest/pxe_service/error_enriching.js +1 -1
  28. package/dest/pxe_service/pxe_service.d.ts +5 -1
  29. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  30. package/dest/pxe_service/pxe_service.js +30 -31
  31. package/dest/simulator/index.d.ts +2 -2
  32. package/dest/simulator/index.d.ts.map +1 -1
  33. package/dest/simulator/index.js +4 -4
  34. package/dest/simulator_oracle/index.d.ts +16 -9
  35. package/dest/simulator_oracle/index.d.ts.map +1 -1
  36. package/dest/simulator_oracle/index.js +131 -63
  37. package/dest/utils/create_pxe_service.d.ts.map +1 -1
  38. package/dest/utils/create_pxe_service.js +9 -12
  39. package/package.json +14 -15
  40. package/src/config/index.ts +2 -1
  41. package/src/database/kv_pxe_database.ts +62 -0
  42. package/src/database/note_dao.ts +2 -30
  43. package/src/database/outgoing_note_dao.ts +1 -28
  44. package/src/database/pxe_database.ts +37 -0
  45. package/src/database/pxe_database_test_suite.ts +160 -0
  46. package/src/kernel_oracle/index.ts +1 -1
  47. package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +4 -4
  48. package/src/kernel_prover/index.ts +0 -2
  49. package/src/kernel_prover/kernel_prover.ts +58 -20
  50. package/src/note_decryption_utils/add_public_values_to_payload.ts +1 -1
  51. package/src/pxe_service/error_enriching.ts +1 -1
  52. package/src/pxe_service/pxe_service.ts +32 -44
  53. package/src/simulator/index.ts +4 -2
  54. package/src/simulator_oracle/index.ts +224 -67
  55. package/src/utils/create_pxe_service.ts +8 -13
  56. package/dest/kernel_prover/test/test_circuit_prover.d.ts +0 -20
  57. package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +0 -1
  58. package/dest/kernel_prover/test/test_circuit_prover.js +0 -75
  59. package/dest/note_decryption_utils/brute_force_note_info.d.ts +0 -31
  60. package/dest/note_decryption_utils/brute_force_note_info.d.ts.map +0 -1
  61. package/dest/note_decryption_utils/brute_force_note_info.js +0 -55
  62. package/dest/note_decryption_utils/index.d.ts +0 -3
  63. package/dest/note_decryption_utils/index.d.ts.map +0 -1
  64. package/dest/note_decryption_utils/index.js +0 -2
  65. package/dest/note_decryption_utils/produce_note_daos.d.ts +0 -28
  66. package/dest/note_decryption_utils/produce_note_daos.d.ts.map +0 -1
  67. package/dest/note_decryption_utils/produce_note_daos.js +0 -33
  68. package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +0 -8
  69. package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +0 -1
  70. package/dest/note_decryption_utils/produce_note_daos_for_key.js +0 -17
  71. package/src/kernel_prover/test/test_circuit_prover.ts +0 -122
  72. package/src/note_decryption_utils/brute_force_note_info.ts +0 -90
  73. package/src/note_decryption_utils/index.ts +0 -2
  74. package/src/note_decryption_utils/produce_note_daos.ts +0 -67
  75. package/src/note_decryption_utils/produce_note_daos_for_key.ts +0 -57
@@ -65,7 +65,7 @@ import { type KeyStore } from '@aztec/key-store';
65
65
  import { type L2TipsStore } from '@aztec/kv-store/stores';
66
66
  import { ProtocolContractAddress, protocolContractNames } from '@aztec/protocol-contracts';
67
67
  import { getCanonicalProtocolContract } from '@aztec/protocol-contracts/bundle';
68
- import { type AcirSimulator } from '@aztec/simulator/client';
68
+ import { type AcirSimulator, type SimulationProvider } from '@aztec/simulator/client';
69
69
 
70
70
  import { inspect } from 'util';
71
71
 
@@ -75,8 +75,7 @@ import { ContractDataOracle } from '../contract_data_oracle/index.js';
75
75
  import { type PxeDatabase } from '../database/index.js';
76
76
  import { NoteDao } from '../database/note_dao.js';
77
77
  import { KernelOracle } from '../kernel_oracle/index.js';
78
- import { KernelProver } from '../kernel_prover/kernel_prover.js';
79
- import { TestPrivateKernelProver } from '../kernel_prover/test/test_circuit_prover.js';
78
+ import { KernelProver, type ProvingConfig } from '../kernel_prover/kernel_prover.js';
80
79
  import { getAcirSimulator } from '../simulator/index.js';
81
80
  import { Synchronizer } from '../synchronizer/index.js';
82
81
  import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js';
@@ -90,6 +89,7 @@ export class PXEService implements PXE {
90
89
  private simulator: AcirSimulator;
91
90
  private log: Logger;
92
91
  private packageVersion: string;
92
+ private proverEnabled: boolean;
93
93
 
94
94
  constructor(
95
95
  private keyStore: KeyStore,
@@ -97,14 +97,16 @@ export class PXEService implements PXE {
97
97
  private db: PxeDatabase,
98
98
  tipsStore: L2TipsStore,
99
99
  private proofCreator: PrivateKernelProver,
100
+ private simulationProvider: SimulationProvider,
100
101
  config: PXEServiceConfig,
101
102
  logSuffix?: string,
102
103
  ) {
103
104
  this.log = createLogger(logSuffix ? `pxe:service:${logSuffix}` : `pxe:service`);
104
105
  this.synchronizer = new Synchronizer(node, db, tipsStore, config, logSuffix);
105
106
  this.contractDataOracle = new ContractDataOracle(db);
106
- this.simulator = getAcirSimulator(db, node, keyStore, this.contractDataOracle);
107
+ this.simulator = getAcirSimulator(db, node, keyStore, this.simulationProvider, this.contractDataOracle);
107
108
  this.packageVersion = getPackageInfo().version;
109
+ this.proverEnabled = !!config.proverEnabled;
108
110
  }
109
111
 
110
112
  /**
@@ -305,6 +307,10 @@ export class PXEService implements PXE {
305
307
  return await getNonNullifiedL1ToL2MessageWitness(this.node, contractAddress, messageHash, secret);
306
308
  }
307
309
 
310
+ public getL2ToL1MembershipWitness(blockNumber: number, l2Tol1Message: Fr): Promise<[bigint, SiblingPath<number>]> {
311
+ return this.node.getL2ToL1MessageMembershipWitness(blockNumber, l2Tol1Message);
312
+ }
313
+
308
314
  public async addNote(note: ExtendedNote, scope?: AztecAddress) {
309
315
  const owner = await this.db.getCompleteAddress(note.owner);
310
316
  if (!owner) {
@@ -453,20 +459,16 @@ export class PXEService implements PXE {
453
459
  return await this.node.getCurrentBaseFees();
454
460
  }
455
461
 
456
- async #simulateKernels(
457
- txRequest: TxExecutionRequest,
458
- privateExecutionResult: PrivateExecutionResult,
459
- ): Promise<PrivateKernelTailCircuitPublicInputs> {
460
- const result = await this.#prove(txRequest, new TestPrivateKernelProver(), privateExecutionResult);
461
- return result.publicInputs;
462
- }
463
-
464
462
  public async proveTx(
465
463
  txRequest: TxExecutionRequest,
466
464
  privateExecutionResult: PrivateExecutionResult,
467
465
  ): Promise<TxProvingResult> {
468
466
  try {
469
- const { publicInputs, clientIvcProof } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult);
467
+ const { publicInputs, clientIvcProof } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
468
+ simulate: false,
469
+ profile: false,
470
+ dryRun: false,
471
+ });
470
472
  return new TxProvingResult(privateExecutionResult, publicInputs, clientIvcProof!);
471
473
  } catch (err: any) {
472
474
  throw this.contextualizeError(err, inspect(txRequest), inspect(privateExecutionResult));
@@ -501,17 +503,11 @@ export class PXEService implements PXE {
501
503
  await this.synchronizer.sync();
502
504
  const privateExecutionResult = await this.#executePrivate(txRequest, msgSender, scopes);
503
505
 
504
- let publicInputs: PrivateKernelTailCircuitPublicInputs;
505
- let profileResult;
506
- if (profile) {
507
- ({ publicInputs, profileResult } = await this.#profileKernelProver(
508
- txRequest,
509
- this.proofCreator,
510
- privateExecutionResult,
511
- ));
512
- } else {
513
- publicInputs = await this.#simulateKernels(txRequest, privateExecutionResult);
514
- }
506
+ const { publicInputs, profileResult } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
507
+ simulate: !profile,
508
+ profile,
509
+ dryRun: true,
510
+ });
515
511
 
516
512
  const privateSimulationResult = new PrivateSimulationResult(privateExecutionResult, publicInputs);
517
513
  const simulatedTx = privateSimulationResult.toSimulatedTx();
@@ -526,8 +522,8 @@ export class PXEService implements PXE {
526
522
  }
527
523
  }
528
524
 
529
- this.log.info(`Simulation completed for ${simulatedTx.tryGetTxHash()} in ${timer.ms()}ms`, {
530
- txHash: simulatedTx.tryGetTxHash(),
525
+ this.log.info(`Simulation completed for ${simulatedTx.getTxHash()} in ${timer.ms()}ms`, {
526
+ txHash: simulatedTx.getTxHash(),
531
527
  ...txInfo,
532
528
  ...(profileResult ? { gateCounts: profileResult.gateCounts } : {}),
533
529
  ...(publicOutput
@@ -795,20 +791,6 @@ export class PXEService implements PXE {
795
791
  }
796
792
  }
797
793
 
798
- async #profileKernelProver(
799
- txExecutionRequest: TxExecutionRequest,
800
- proofCreator: PrivateKernelProver,
801
- privateExecutionResult: PrivateExecutionResult,
802
- ): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
803
- const block = privateExecutionResult.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
804
- const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block);
805
- const kernelProver = new KernelProver(kernelOracle, proofCreator);
806
-
807
- // Dry run the prover with profiler enabled
808
- const result = await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, true, true);
809
- return result;
810
- }
811
-
812
794
  /**
813
795
  * Generate a kernel proof, and create a private kernel output.
814
796
  * The function takes in a transaction execution request, and the result of private execution
@@ -823,13 +805,19 @@ export class PXEService implements PXE {
823
805
  txExecutionRequest: TxExecutionRequest,
824
806
  proofCreator: PrivateKernelProver,
825
807
  privateExecutionResult: PrivateExecutionResult,
808
+ { simulate, profile, dryRun }: ProvingConfig,
826
809
  ): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
827
810
  // use the block the tx was simulated against
828
- const block = privateExecutionResult.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
811
+ const block =
812
+ privateExecutionResult.entrypoint.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
829
813
  const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block);
830
- const kernelProver = new KernelProver(kernelOracle, proofCreator);
831
- this.log.debug(`Executing kernel prover...`);
832
- return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult);
814
+ const kernelProver = new KernelProver(kernelOracle, proofCreator, !this.proverEnabled);
815
+ this.log.debug(`Executing kernel prover (simulate: ${simulate}, profile: ${profile}, dryRun: ${dryRun})...`);
816
+ return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, {
817
+ simulate,
818
+ profile,
819
+ dryRun,
820
+ });
833
821
  }
834
822
 
835
823
  public async isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
@@ -1,6 +1,6 @@
1
1
  import { type AztecNode } from '@aztec/circuit-types';
2
2
  import { type KeyStore } from '@aztec/key-store';
3
- import { AcirSimulator } from '@aztec/simulator/client';
3
+ import { AcirSimulator, type SimulationProvider } from '@aztec/simulator/client';
4
4
 
5
5
  import { ContractDataOracle } from '../contract_data_oracle/index.js';
6
6
  import { type PxeDatabase } from '../database/pxe_database.js';
@@ -13,6 +13,7 @@ export function getAcirSimulator(
13
13
  db: PxeDatabase,
14
14
  aztecNode: AztecNode,
15
15
  keyStore: KeyStore,
16
+ simulationProvider: SimulationProvider,
16
17
  contractDataOracle?: ContractDataOracle,
17
18
  ) {
18
19
  const simulatorOracle = new SimulatorOracle(
@@ -20,6 +21,7 @@ export function getAcirSimulator(
20
21
  db,
21
22
  keyStore,
22
23
  aztecNode,
24
+ simulationProvider,
23
25
  );
24
- return new AcirSimulator(simulatorOracle, aztecNode);
26
+ return new AcirSimulator(simulatorOracle, aztecNode, simulationProvider);
25
27
  }
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  type AztecNode,
3
+ type FunctionCall,
3
4
  type InBlock,
4
5
  L1NotePayload,
5
6
  type L2Block,
6
7
  type L2BlockNumber,
7
8
  MerkleTreeId,
9
+ Note,
8
10
  type NoteStatus,
9
11
  type NullifierMembershipWitness,
10
12
  type PublicDataWitness,
11
- type TxEffect,
13
+ TxHash,
12
14
  type TxScopedL2Log,
13
15
  getNonNullifiedL1ToL2MessageWitness,
14
16
  } from '@aztec/circuit-types';
@@ -18,25 +20,38 @@ import {
18
20
  type CompleteAddress,
19
21
  type ContractInstance,
20
22
  Fr,
21
- type FunctionSelector,
23
+ FunctionSelector,
22
24
  IndexedTaggingSecret,
23
25
  type KeyValidationRequest,
24
26
  type L1_TO_L2_MSG_TREE_HEIGHT,
27
+ MAX_NOTE_HASHES_PER_TX,
28
+ PRIVATE_LOG_SIZE_IN_FIELDS,
25
29
  PrivateLog,
26
30
  computeAddressSecret,
27
31
  computeTaggingSecretPoint,
28
32
  } from '@aztec/circuits.js';
29
- import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi';
33
+ import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
34
+ import {
35
+ type FunctionArtifact,
36
+ FunctionType,
37
+ NoteSelector,
38
+ encodeArguments,
39
+ getFunctionArtifact,
40
+ } from '@aztec/foundation/abi';
30
41
  import { poseidon2Hash } from '@aztec/foundation/crypto';
31
42
  import { createLogger } from '@aztec/foundation/log';
32
43
  import { type KeyStore } from '@aztec/key-store';
33
- import { MessageLoadOracleInputs } from '@aztec/simulator/acvm';
34
- import { type AcirSimulator, type DBOracle } from '@aztec/simulator/client';
44
+ import {
45
+ type AcirSimulator,
46
+ type DBOracle,
47
+ MessageLoadOracleInputs,
48
+ type SimulationProvider,
49
+ } from '@aztec/simulator/client';
35
50
 
36
- import { type ContractDataOracle } from '../contract_data_oracle/index.js';
51
+ import { ContractDataOracle } from '../contract_data_oracle/index.js';
37
52
  import { type PxeDatabase } from '../database/index.js';
38
- import { type NoteDao } from '../database/note_dao.js';
39
- import { produceNoteDaos } from '../note_decryption_utils/produce_note_daos.js';
53
+ import { NoteDao } from '../database/note_dao.js';
54
+ import { getOrderedNoteItems } from '../note_decryption_utils/add_public_values_to_payload.js';
40
55
  import { getAcirSimulator } from '../simulator/index.js';
41
56
  import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
42
57
 
@@ -49,6 +64,7 @@ export class SimulatorOracle implements DBOracle {
49
64
  private db: PxeDatabase,
50
65
  private keyStore: KeyStore,
51
66
  private aztecNode: AztecNode,
67
+ private simulationProvider: SimulationProvider,
52
68
  private log = createLogger('pxe:simulator_oracle'),
53
69
  ) {}
54
70
 
@@ -163,7 +179,7 @@ export class SimulatorOracle implements DBOracle {
163
179
  * @returns - The index of the commitment. Undefined if it does not exist in the tree.
164
180
  */
165
181
  async getCommitmentIndex(commitment: Fr) {
166
- return await this.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
182
+ return await this.#findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
167
183
  }
168
184
 
169
185
  // We need this in public as part of the EXISTS calls - but isn't used in private
@@ -172,19 +188,26 @@ export class SimulatorOracle implements DBOracle {
172
188
  }
173
189
 
174
190
  async getNullifierIndex(nullifier: Fr) {
175
- return await this.findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
191
+ return await this.#findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
176
192
  }
177
193
 
178
- public async findLeafIndex(
179
- blockNumber: L2BlockNumber,
180
- treeId: MerkleTreeId,
181
- leafValue: Fr,
182
- ): Promise<bigint | undefined> {
194
+ async #findLeafIndex(blockNumber: L2BlockNumber, treeId: MerkleTreeId, leafValue: Fr): Promise<bigint | undefined> {
183
195
  const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [leafValue]);
184
196
  return leafIndex;
185
197
  }
186
198
 
187
- public async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: bigint): Promise<Fr[]> {
199
+ public async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[]> {
200
+ const leafIndex = await this.#findLeafIndex(blockNumber, treeId, leafValue);
201
+ if (!leafIndex) {
202
+ throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]}`);
203
+ }
204
+
205
+ const siblingPath = await this.#getSiblingPath(blockNumber, treeId, leafIndex);
206
+
207
+ return [new Fr(leafIndex), ...siblingPath];
208
+ }
209
+
210
+ async #getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: bigint): Promise<Fr[]> {
188
211
  switch (treeId) {
189
212
  case MerkleTreeId.NULLIFIER_TREE:
190
213
  return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields();
@@ -419,6 +442,8 @@ export class SimulatorOracle implements DBOracle {
419
442
  maxBlockNumber: number,
420
443
  scopes?: AztecAddress[],
421
444
  ): Promise<Map<string, TxScopedL2Log[]>> {
445
+ this.log.verbose('Searching for tagged logs', { contract: contractAddress });
446
+
422
447
  // Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
423
448
  // However it is impossible at the moment due to the language not supporting nested slices.
424
449
  // This nesting is necessary because for a given set of tags we don't
@@ -556,10 +581,9 @@ export class SimulatorOracle implements DBOracle {
556
581
  * Decrypts logs tagged for a recipient and returns them.
557
582
  * @param scopedLogs - The logs to decrypt.
558
583
  * @param recipient - The recipient of the logs.
559
- * @param simulator - The simulator to use for decryption.
560
584
  * @returns The decrypted notes.
561
585
  */
562
- async #decryptTaggedLogs(scopedLogs: TxScopedL2Log[], recipient: AztecAddress, simulator?: AcirSimulator) {
586
+ async #decryptTaggedLogs(scopedLogs: TxScopedL2Log[], recipient: AztecAddress) {
563
587
  const recipientCompleteAddress = await this.getCompleteAddress(recipient);
564
588
  const ivskM = await this.keyStore.getMasterSecretKey(
565
589
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
@@ -569,54 +593,29 @@ export class SimulatorOracle implements DBOracle {
569
593
  // Since we could have notes with the same index for different txs, we need
570
594
  // to keep track of them scoping by txHash
571
595
  const excludedIndices: Map<string, Set<number>> = new Map();
572
- const notes: NoteDao[] = [];
573
-
574
- const txEffectsCache = new Map<string, InBlock<TxEffect> | undefined>();
596
+ const decrypted = [];
575
597
 
576
598
  for (const scopedLog of scopedLogs) {
577
- const notePayload = scopedLog.isFromPublic
599
+ const payload = scopedLog.isFromPublic
578
600
  ? L1NotePayload.decryptAsIncomingFromPublic(scopedLog.logData, addressSecret)
579
601
  : L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
580
602
 
581
- if (notePayload) {
582
- const payload = notePayload;
583
-
584
- const txEffect =
585
- txEffectsCache.get(scopedLog.txHash.toString()) ?? (await this.aztecNode.getTxEffect(scopedLog.txHash));
586
-
587
- if (!txEffect) {
588
- this.log.warn(`No tx effect found for ${scopedLog.txHash} while decrypting tagged logs`);
589
- continue;
590
- }
603
+ if (!payload) {
604
+ this.log.verbose('Unable to decrypt log');
605
+ continue;
606
+ }
591
607
 
592
- txEffectsCache.set(scopedLog.txHash.toString(), txEffect);
608
+ if (!excludedIndices.has(scopedLog.txHash.toString())) {
609
+ excludedIndices.set(scopedLog.txHash.toString(), new Set());
610
+ }
593
611
 
594
- if (!excludedIndices.has(scopedLog.txHash.toString())) {
595
- excludedIndices.set(scopedLog.txHash.toString(), new Set());
596
- }
597
- const { note } = await produceNoteDaos(
598
- // I don't like this at all, but we need a simulator to run `computeNoteHashAndOptionallyANullifier`. This generates
599
- // a chicken-and-egg problem due to this oracle requiring a simulator, which in turn requires this oracle. Furthermore, since jest doesn't allow
600
- // mocking ESM exports, we have to pollute the method even more by providing a simulator parameter so tests can inject a fake one.
601
- simulator ?? getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.contractDataOracle),
602
- this.db,
603
- notePayload ? recipient.toAddressPoint() : undefined,
604
- payload!,
605
- txEffect.data.txHash,
606
- txEffect.l2BlockNumber,
607
- txEffect.l2BlockHash,
608
- txEffect.data.noteHashes,
609
- scopedLog.dataStartIndexForTx,
610
- excludedIndices.get(scopedLog.txHash.toString())!,
611
- this.log,
612
- );
612
+ const note = await getOrderedNoteItems(this.db, payload);
613
+ const plaintext = [payload.storageSlot, payload.noteTypeId.toField(), ...note.items];
613
614
 
614
- if (note) {
615
- notes.push(note);
616
- }
617
- }
615
+ decrypted.push({ plaintext, txHash: scopedLog.txHash, contractAddress: payload.contractAddress });
618
616
  }
619
- return { notes };
617
+
618
+ return decrypted;
620
619
  }
621
620
 
622
621
  /**
@@ -629,20 +628,68 @@ export class SimulatorOracle implements DBOracle {
629
628
  recipient: AztecAddress,
630
629
  simulator?: AcirSimulator,
631
630
  ): Promise<void> {
632
- const { notes } = await this.#decryptTaggedLogs(logs, recipient, simulator);
633
- if (notes.length) {
634
- await this.db.addNotes(notes, recipient);
635
- notes.forEach(noteDao => {
636
- this.log.verbose(`Added incoming note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
637
- contract: noteDao.contractAddress,
638
- slot: noteDao.storageSlot,
639
- nullifier: noteDao.siloedNullifier.toString(),
640
- });
641
- });
631
+ const decryptedLogs = await this.#decryptTaggedLogs(logs, recipient);
632
+
633
+ // We've produced the full NoteDao, which we'd be able to simply insert into the database. However, this is
634
+ // only a temporary measure as we migrate from the PXE-driven discovery into the new contract-driven approach. We
635
+ // discard most of the work done up to this point and reconstruct the note plaintext to then hand over to the
636
+ // contract for further processing.
637
+ for (const decryptedLog of decryptedLogs) {
638
+ // Log processing requires the note hashes in the tx in which the note was created. We are now assuming that the
639
+ // note was included in the same block in which the log was delivered - note that partial notes will not work this
640
+ // way.
641
+ const txEffect = await this.aztecNode.getTxEffect(decryptedLog.txHash);
642
+ if (!txEffect) {
643
+ throw new Error(`Could not find tx effect for tx hash ${decryptedLog.txHash}`);
644
+ }
645
+
646
+ // This will trigger calls to the deliverNote oracle
647
+ await this.callProcessLog(
648
+ decryptedLog.contractAddress,
649
+ decryptedLog.plaintext,
650
+ decryptedLog.txHash,
651
+ txEffect.data.noteHashes,
652
+ txEffect.data.nullifiers[0],
653
+ recipient,
654
+ simulator,
655
+ );
642
656
  }
657
+ return;
658
+ }
659
+
660
+ // Called when notes are delivered, usually as a result to a call to the process_log contract function
661
+ public async deliverNote(
662
+ contractAddress: AztecAddress,
663
+ storageSlot: Fr,
664
+ nonce: Fr,
665
+ content: Fr[],
666
+ noteHash: Fr,
667
+ nullifier: Fr,
668
+ txHash: Fr,
669
+ recipient: AztecAddress,
670
+ ): Promise<void> {
671
+ const noteDao = await this.produceNoteDao(
672
+ contractAddress,
673
+ storageSlot,
674
+ nonce,
675
+ content,
676
+ noteHash,
677
+ nullifier,
678
+ txHash,
679
+ recipient,
680
+ );
681
+
682
+ await this.db.addNotes([noteDao], recipient);
683
+ this.log.verbose('Added note', {
684
+ contract: noteDao.contractAddress,
685
+ slot: noteDao.storageSlot,
686
+ nullifier: noteDao.siloedNullifier.toString,
687
+ });
643
688
  }
644
689
 
645
690
  public async removeNullifiedNotes(contractAddress: AztecAddress) {
691
+ this.log.verbose('Removing nullified notes', { contract: contractAddress });
692
+
646
693
  for (const recipient of await this.keyStore.getAccounts()) {
647
694
  const currentNotesForRecipient = await this.db.getNotes({ contractAddress, owner: recipient });
648
695
  const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
@@ -666,4 +713,114 @@ export class SimulatorOracle implements DBOracle {
666
713
  });
667
714
  }
668
715
  }
716
+
717
+ async produceNoteDao(
718
+ contractAddress: AztecAddress,
719
+ storageSlot: Fr,
720
+ nonce: Fr,
721
+ content: Fr[],
722
+ noteHash: Fr,
723
+ nullifier: Fr,
724
+ txHash: Fr,
725
+ recipient: AztecAddress,
726
+ ): Promise<NoteDao> {
727
+ const receipt = await this.aztecNode.getTxReceipt(new TxHash(txHash));
728
+ if (receipt === undefined) {
729
+ throw new Error(`Failed to fetch tx receipt for tx hash ${txHash} when searching for note hashes`);
730
+ }
731
+ const { blockNumber, blockHash } = receipt;
732
+
733
+ const uniqueNoteHash = computeUniqueNoteHash(nonce, siloNoteHash(contractAddress, noteHash));
734
+ const siloedNullifier = siloNullifier(contractAddress, nullifier);
735
+
736
+ const uniqueNoteHashTreeIndex = (
737
+ await this.aztecNode.findLeavesIndexes(blockNumber!, MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash])
738
+ )[0];
739
+ if (uniqueNoteHashTreeIndex === undefined) {
740
+ throw new Error(
741
+ `Note hash ${noteHash} (uniqued as ${uniqueNoteHash}) is not present on the tree at block ${blockNumber} (from tx ${txHash})`,
742
+ );
743
+ }
744
+
745
+ return new NoteDao(
746
+ new Note(content),
747
+ contractAddress,
748
+ storageSlot,
749
+ nonce,
750
+ noteHash,
751
+ siloedNullifier,
752
+ new TxHash(txHash),
753
+ blockNumber!,
754
+ blockHash!.toString(),
755
+ uniqueNoteHashTreeIndex,
756
+ recipient.toAddressPoint(),
757
+ NoteSelector.empty(), // todo: remove
758
+ );
759
+ }
760
+
761
+ async callProcessLog(
762
+ contractAddress: AztecAddress,
763
+ logPlaintext: Fr[],
764
+ txHash: TxHash,
765
+ noteHashes: Fr[],
766
+ firstNullifier: Fr,
767
+ recipient: AztecAddress,
768
+ simulator?: AcirSimulator,
769
+ ) {
770
+ const artifact: FunctionArtifact | undefined = await new ContractDataOracle(this.db).getFunctionArtifactByName(
771
+ contractAddress,
772
+ 'process_log',
773
+ );
774
+ if (!artifact) {
775
+ throw new Error(
776
+ `Mandatory implementation of "process_log" missing in noir contract ${contractAddress.toString()}.`,
777
+ );
778
+ }
779
+
780
+ const execRequest: FunctionCall = {
781
+ name: artifact.name,
782
+ to: contractAddress,
783
+ selector: FunctionSelector.fromNameAndParameters(artifact),
784
+ type: FunctionType.UNCONSTRAINED,
785
+ isStatic: artifact.isStatic,
786
+ args: encodeArguments(artifact, [
787
+ toBoundedVec(logPlaintext, PRIVATE_LOG_SIZE_IN_FIELDS),
788
+ txHash.toString(),
789
+ toBoundedVec(noteHashes, MAX_NOTE_HASHES_PER_TX),
790
+ firstNullifier,
791
+ recipient,
792
+ ]),
793
+ returnTypes: artifact.returnTypes,
794
+ };
795
+
796
+ await (
797
+ simulator ??
798
+ getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle)
799
+ ).runUnconstrained(
800
+ execRequest,
801
+ artifact,
802
+ contractAddress,
803
+ [], // empty scope as this call should not require access to private information
804
+ );
805
+ }
806
+
807
+ dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise<void> {
808
+ return this.db.dbStore(contractAddress, slot, values);
809
+ }
810
+
811
+ dbLoad(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
812
+ return this.db.dbLoad(contractAddress, slot);
813
+ }
814
+
815
+ dbDelete(contractAddress: AztecAddress, slot: Fr): Promise<void> {
816
+ return this.db.dbDelete(contractAddress, slot);
817
+ }
818
+
819
+ dbCopy(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
820
+ return this.db.dbCopy(contractAddress, srcSlot, dstSlot, numEntries);
821
+ }
822
+ }
823
+
824
+ function toBoundedVec(array: Fr[], maxLength: number) {
825
+ return { storage: array.concat(Array(maxLength - array.length).fill(new Fr(0))), len: array.length };
669
826
  }
@@ -1,15 +1,15 @@
1
1
  import { BBNativePrivateKernelProver } from '@aztec/bb-prover';
2
- import { BBWasmPrivateKernelProver } from '@aztec/bb-prover/wasm';
2
+ import { BBWASMBundlePrivateKernelProver } from '@aztec/bb-prover/wasm/bundle';
3
3
  import { type AztecNode, type PrivateKernelProver } from '@aztec/circuit-types';
4
4
  import { randomBytes } from '@aztec/foundation/crypto';
5
5
  import { createLogger } from '@aztec/foundation/log';
6
6
  import { KeyStore } from '@aztec/key-store';
7
7
  import { createStore } from '@aztec/kv-store/lmdb';
8
8
  import { L2TipsStore } from '@aztec/kv-store/stores';
9
+ import { type SimulationProvider, WASMSimulator } from '@aztec/simulator/client';
9
10
 
10
11
  import { type PXEServiceConfig } from '../config/index.js';
11
12
  import { KVPxeDatabase } from '../database/kv_pxe_database.js';
12
- import { TestPrivateKernelProver } from '../kernel_prover/test/test_circuit_prover.js';
13
13
  import { PXEService } from '../pxe_service/pxe_service.js';
14
14
 
15
15
  /**
@@ -46,25 +46,20 @@ export async function createPXEService(
46
46
 
47
47
  const db = await KVPxeDatabase.create(store);
48
48
  const tips = new L2TipsStore(store, 'pxe');
49
-
50
- const prover = proofCreator ?? (await createProver(config, logSuffix));
51
- const pxe = new PXEService(keyStore, aztecNode, db, tips, prover, config, logSuffix);
49
+ const simulationProvider = new WASMSimulator();
50
+ const prover = proofCreator ?? (await createProver(config, simulationProvider, logSuffix));
51
+ const pxe = new PXEService(keyStore, aztecNode, db, tips, prover, simulationProvider, config, logSuffix);
52
52
  await pxe.init();
53
53
  return pxe;
54
54
  }
55
55
 
56
- function createProver(config: PXEServiceConfig, logSuffix?: string) {
57
- if (!config.proverEnabled) {
58
- return new TestPrivateKernelProver();
59
- }
60
-
61
- // (@PhilWindle) Temporary validation until WASM is implemented
56
+ function createProver(config: PXEServiceConfig, simulationProvider: SimulationProvider, logSuffix?: string) {
62
57
  if (!config.bbBinaryPath || !config.bbWorkingDirectory) {
63
- return new BBWasmPrivateKernelProver(16);
58
+ return new BBWASMBundlePrivateKernelProver(simulationProvider, 16);
64
59
  } else {
65
60
  const bbConfig = config as Required<Pick<PXEServiceConfig, 'bbBinaryPath' | 'bbWorkingDirectory'>> &
66
61
  PXEServiceConfig;
67
62
  const log = createLogger('pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
68
- return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, log);
63
+ return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, simulationProvider, log);
69
64
  }
70
65
  }
@@ -1,20 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- import { type PrivateKernelProver, type PrivateKernelSimulateOutput } from '@aztec/circuit-types';
4
- import { ClientIvcProof, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelResetCircuitPrivateInputs, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs } from '@aztec/circuits.js';
5
- import { type WitnessMap } from '@noir-lang/types';
6
- /**
7
- * Test Proof Creator executes circuit simulations and provides fake proofs.
8
- */
9
- export declare class TestPrivateKernelProver implements PrivateKernelProver {
10
- private log;
11
- constructor(log?: import("@aztec/foundation/log").Logger);
12
- createClientIvcProof(_acirs: Buffer[], _witnessStack: WitnessMap[]): Promise<ClientIvcProof>;
13
- simulateProofInit(privateInputs: PrivateKernelInitCircuitPrivateInputs): Promise<PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>>;
14
- simulateProofInner(privateInputs: PrivateKernelInnerCircuitPrivateInputs): Promise<PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>>;
15
- simulateProofReset(privateInputs: PrivateKernelResetCircuitPrivateInputs): Promise<PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>>;
16
- simulateProofTail(privateInputs: PrivateKernelTailCircuitPrivateInputs): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>>;
17
- computeGateCountForCircuit(_bytecode: Buffer, _circuitName: string): Promise<number>;
18
- private makeEmptyKernelSimulateOutput;
19
- }
20
- //# sourceMappingURL=test_circuit_prover.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test_circuit_prover.d.ts","sourceRoot":"","sources":["../../../src/kernel_prover/test/test_circuit_prover.ts"],"names":[],"mappings":";;AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAElG,OAAO,EACL,cAAc,EACd,KAAK,gCAAgC,EACrC,KAAK,qCAAqC,EAC1C,KAAK,sCAAsC,EAC3C,KAAK,sCAAsC,EAC3C,KAAK,qCAAqC,EAC1C,KAAK,oCAAoC,EAC1C,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;GAEG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACrD,OAAO,CAAC,GAAG;gBAAH,GAAG,yCAAyC;IAEhE,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAI/E,iBAAiB,CAC5B,aAAa,EAAE,qCAAqC,GACnD,OAAO,CAAC,2BAA2B,CAAC,gCAAgC,CAAC,CAAC;IAY5D,kBAAkB,CAC7B,aAAa,EAAE,sCAAsC,GACpD,OAAO,CAAC,2BAA2B,CAAC,gCAAgC,CAAC,CAAC;IAY5D,kBAAkB,CAC7B,aAAa,EAAE,sCAAsC,GACpD,OAAO,CAAC,2BAA2B,CAAC,gCAAgC,CAAC,CAAC;IAkB5D,iBAAiB,CAC5B,aAAa,EAAE,qCAAqC,GACnD,OAAO,CAAC,2BAA2B,CAAC,oCAAoC,CAAC,CAAC;IAkBtE,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK3F,OAAO,CAAC,6BAA6B;CAWtC"}