@aztec/pxe 0.8.6

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 (114) hide show
  1. package/README.md +13 -0
  2. package/dest/bin/index.d.ts +3 -0
  3. package/dest/bin/index.d.ts.map +1 -0
  4. package/dest/bin/index.js +31 -0
  5. package/dest/config/index.d.ts +21 -0
  6. package/dest/config/index.d.ts.map +1 -0
  7. package/dest/config/index.js +21 -0
  8. package/dest/contract_data_oracle/index.d.ts +99 -0
  9. package/dest/contract_data_oracle/index.d.ts.map +1 -0
  10. package/dest/contract_data_oracle/index.js +137 -0
  11. package/dest/contract_database/index.d.ts +2 -0
  12. package/dest/contract_database/index.d.ts.map +1 -0
  13. package/dest/contract_database/index.js +2 -0
  14. package/dest/contract_database/memory_contract_database.d.ts +43 -0
  15. package/dest/contract_database/memory_contract_database.d.ts.map +1 -0
  16. package/dest/contract_database/memory_contract_database.js +51 -0
  17. package/dest/contract_tree/index.d.ts +107 -0
  18. package/dest/contract_tree/index.d.ts.map +1 -0
  19. package/dest/contract_tree/index.js +181 -0
  20. package/dest/database/database.d.ts +118 -0
  21. package/dest/database/database.d.ts.map +1 -0
  22. package/dest/database/database.js +2 -0
  23. package/dest/database/index.d.ts +4 -0
  24. package/dest/database/index.d.ts.map +1 -0
  25. package/dest/database/index.js +4 -0
  26. package/dest/database/memory_db.d.ts +45 -0
  27. package/dest/database/memory_db.d.ts.map +1 -0
  28. package/dest/database/memory_db.js +111 -0
  29. package/dest/database/note_spending_info_dao.d.ts +44 -0
  30. package/dest/database/note_spending_info_dao.d.ts.map +1 -0
  31. package/dest/database/note_spending_info_dao.js +14 -0
  32. package/dest/index.d.ts +10 -0
  33. package/dest/index.d.ts.map +1 -0
  34. package/dest/index.js +10 -0
  35. package/dest/kernel_oracle/index.d.ts +18 -0
  36. package/dest/kernel_oracle/index.d.ts.map +1 -0
  37. package/dest/kernel_oracle/index.js +29 -0
  38. package/dest/kernel_prover/index.d.ts +3 -0
  39. package/dest/kernel_prover/index.d.ts.map +1 -0
  40. package/dest/kernel_prover/index.js +3 -0
  41. package/dest/kernel_prover/kernel_prover.d.ts +89 -0
  42. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -0
  43. package/dest/kernel_prover/kernel_prover.js +175 -0
  44. package/dest/kernel_prover/proof_creator.d.ts +84 -0
  45. package/dest/kernel_prover/proof_creator.d.ts.map +1 -0
  46. package/dest/kernel_prover/proof_creator.js +83 -0
  47. package/dest/kernel_prover/proving_data_oracle.d.ts +53 -0
  48. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -0
  49. package/dest/kernel_prover/proving_data_oracle.js +2 -0
  50. package/dest/note_processor/index.d.ts +2 -0
  51. package/dest/note_processor/index.d.ts.map +1 -0
  52. package/dest/note_processor/index.js +2 -0
  53. package/dest/note_processor/note_processor.d.ts +78 -0
  54. package/dest/note_processor/note_processor.d.ts.map +1 -0
  55. package/dest/note_processor/note_processor.js +206 -0
  56. package/dest/pxe_http/index.d.ts +2 -0
  57. package/dest/pxe_http/index.d.ts.map +1 -0
  58. package/dest/pxe_http/index.js +2 -0
  59. package/dest/pxe_http/pxe_http_server.d.ts +40 -0
  60. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -0
  61. package/dest/pxe_http/pxe_http_server.js +44 -0
  62. package/dest/pxe_service/create_pxe_service.d.ts +30 -0
  63. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -0
  64. package/dest/pxe_service/create_pxe_service.js +27 -0
  65. package/dest/pxe_service/index.d.ts +4 -0
  66. package/dest/pxe_service/index.d.ts.map +1 -0
  67. package/dest/pxe_service/index.js +4 -0
  68. package/dest/pxe_service/pxe_service.d.ts +70 -0
  69. package/dest/pxe_service/pxe_service.d.ts.map +1 -0
  70. package/dest/pxe_service/pxe_service.js +470 -0
  71. package/dest/pxe_service/test/pxe_test_suite.d.ts +3 -0
  72. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -0
  73. package/dest/pxe_service/test/pxe_test_suite.js +100 -0
  74. package/dest/simulator/index.d.ts +9 -0
  75. package/dest/simulator/index.d.ts.map +1 -0
  76. package/dest/simulator/index.js +11 -0
  77. package/dest/simulator_oracle/index.d.ts +53 -0
  78. package/dest/simulator_oracle/index.d.ts.map +1 -0
  79. package/dest/simulator_oracle/index.js +91 -0
  80. package/dest/synchronizer/index.d.ts +2 -0
  81. package/dest/synchronizer/index.d.ts.map +1 -0
  82. package/dest/synchronizer/index.js +2 -0
  83. package/dest/synchronizer/synchronizer.d.ts +82 -0
  84. package/dest/synchronizer/synchronizer.d.ts.map +1 -0
  85. package/dest/synchronizer/synchronizer.js +241 -0
  86. package/package.json +74 -0
  87. package/src/bin/index.ts +39 -0
  88. package/src/config/index.ts +34 -0
  89. package/src/contract_data_oracle/index.ts +151 -0
  90. package/src/contract_database/index.ts +1 -0
  91. package/src/contract_database/memory_contract_database.ts +58 -0
  92. package/src/contract_tree/index.ts +245 -0
  93. package/src/database/database.ts +131 -0
  94. package/src/database/index.ts +3 -0
  95. package/src/database/memory_db.ts +147 -0
  96. package/src/database/note_spending_info_dao.ts +64 -0
  97. package/src/index.ts +11 -0
  98. package/src/kernel_oracle/index.ts +39 -0
  99. package/src/kernel_prover/index.ts +2 -0
  100. package/src/kernel_prover/kernel_prover.ts +317 -0
  101. package/src/kernel_prover/proof_creator.ts +176 -0
  102. package/src/kernel_prover/proving_data_oracle.ts +69 -0
  103. package/src/note_processor/index.ts +1 -0
  104. package/src/note_processor/note_processor.ts +267 -0
  105. package/src/pxe_http/index.ts +1 -0
  106. package/src/pxe_http/pxe_http_server.ts +70 -0
  107. package/src/pxe_service/create_pxe_service.ts +52 -0
  108. package/src/pxe_service/index.ts +3 -0
  109. package/src/pxe_service/pxe_service.ts +650 -0
  110. package/src/pxe_service/test/pxe_test_suite.ts +138 -0
  111. package/src/simulator/index.ts +24 -0
  112. package/src/simulator_oracle/index.ts +121 -0
  113. package/src/synchronizer/index.ts +1 -0
  114. package/src/synchronizer/synchronizer.ts +285 -0
@@ -0,0 +1,176 @@
1
+ import {
2
+ CircuitError,
3
+ CircuitsWasm,
4
+ KernelCircuitPublicInputs,
5
+ KernelCircuitPublicInputsFinal,
6
+ PrivateCircuitPublicInputs,
7
+ PrivateKernelInputsInit,
8
+ PrivateKernelInputsInner,
9
+ PrivateKernelInputsOrdering,
10
+ Proof,
11
+ makeEmptyProof,
12
+ privateKernelSimInit,
13
+ privateKernelSimInner,
14
+ privateKernelSimOrdering,
15
+ } from '@aztec/circuits.js';
16
+ import { siloCommitment } from '@aztec/circuits.js/abis';
17
+ import { Fr } from '@aztec/foundation/fields';
18
+ import { createDebugLogger } from '@aztec/foundation/log';
19
+ import { elapsed } from '@aztec/foundation/timer';
20
+
21
+ /**
22
+ * Represents the output of the proof creation process for init and inner private kernel circuit.
23
+ * Contains the public inputs required for the init and inner private kernel circuit and the generated proof.
24
+ */
25
+ export interface ProofOutput {
26
+ /**
27
+ * The public inputs required for the proof generation process.
28
+ * Note: C++ side does not define the specific data structure PrivateKernelPublicInputs and therefore
29
+ * would not generate a binding in circuits.gen.ts.
30
+ */
31
+ publicInputs: KernelCircuitPublicInputs;
32
+ /**
33
+ * The zk-SNARK proof for the kernel execution.
34
+ */
35
+ proof: Proof;
36
+ }
37
+
38
+ /**
39
+ * Represents the output of the proof creation process for final ordering private kernel circuit.
40
+ * Contains the public inputs required for the final ordering private kernel circuit and the generated proof.
41
+ */
42
+ export interface ProofOutputFinal {
43
+ /**
44
+ * The public inputs required for the proof generation process.
45
+ * Note: C++ side does not define the specific data structure PrivateKernelPublicInputsFinal and therefore
46
+ * would not generate a binding in circuits.gen.ts.
47
+ */
48
+ publicInputs: KernelCircuitPublicInputsFinal;
49
+ /**
50
+ * The zk-SNARK proof for the kernel execution.
51
+ */
52
+ proof: Proof;
53
+ }
54
+
55
+ /**
56
+ * ProofCreator provides functionality to create and validate proofs, and retrieve
57
+ * siloed commitments necessary for maintaining transaction privacy and security on the network.
58
+ */
59
+ export interface ProofCreator {
60
+ /**
61
+ * Computes the siloed commitments for a given set of public inputs.
62
+ *
63
+ * @param publicInputs - The public inputs containing the contract address and new commitments to be used in generating siloed commitments.
64
+ * @returns An array of Fr (finite field) elements representing the siloed commitments.
65
+ */
66
+ getSiloedCommitments(publicInputs: PrivateCircuitPublicInputs): Promise<Fr[]>;
67
+
68
+ /**
69
+ * Creates a proof output for a given signed transaction request and private call data for the first iteration.
70
+ *
71
+ * @param privateKernelInputsInit - The private data structure for the initial iteration.
72
+ * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
73
+ */
74
+ createProofInit(privateKernelInputsInit: PrivateKernelInputsInit): Promise<ProofOutput>;
75
+
76
+ /**
77
+ * Creates a proof output for a given previous kernel data and private call data for an inner iteration.
78
+ *
79
+ * @param privateKernelInputsInner - The private input data structure for the inner iteration.
80
+ * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
81
+ */
82
+ createProofInner(privateKernelInputsInner: PrivateKernelInputsInner): Promise<ProofOutput>;
83
+
84
+ /**
85
+ * Creates a proof output based on the last inner kernel iteration kernel data for the final ordering iteration.
86
+ *
87
+ * @param privateKernelInputsOrdering - The private input data structure for the final ordering iteration.
88
+ * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
89
+ */
90
+ createProofOrdering(privateKernelInputsOrdering: PrivateKernelInputsOrdering): Promise<ProofOutputFinal>;
91
+ }
92
+
93
+ /**
94
+ * The KernelProofCreator class is responsible for generating siloed commitments and zero-knowledge proofs
95
+ * for private kernel circuit. It leverages Barretenberg and Circuits Wasm libraries
96
+ * to perform cryptographic operations and proof creation. The class provides methods to compute commitments
97
+ * based on the given public inputs and to generate proofs based on signed transaction requests, previous kernel
98
+ * data, private call data, and a flag indicating whether it's the first iteration or not.
99
+ */
100
+ export class KernelProofCreator implements ProofCreator {
101
+ constructor(private log = createDebugLogger('aztec:kernel_proof_creator')) {}
102
+
103
+ public async getSiloedCommitments(publicInputs: PrivateCircuitPublicInputs) {
104
+ const wasm = await CircuitsWasm.get();
105
+ const contractAddress = publicInputs.callContext.storageContractAddress;
106
+
107
+ return publicInputs.newCommitments.map(commitment => siloCommitment(wasm, contractAddress, commitment));
108
+ }
109
+
110
+ public async createProofInit(privateInputs: PrivateKernelInputsInit): Promise<ProofOutput> {
111
+ const wasm = await CircuitsWasm.get();
112
+ const [time, result] = await elapsed(() => privateKernelSimInit(wasm, privateInputs));
113
+ if (result instanceof CircuitError) {
114
+ throw new CircuitError(result.code, result.message);
115
+ }
116
+ this.log(`Simulated private kernel init`, {
117
+ eventName: 'circuit-simulation',
118
+ circuitName: 'private-kernel-init',
119
+ duration: time.ms(),
120
+ inputSize: privateInputs.toBuffer().length,
121
+ outputSize: result.toBuffer().length,
122
+ });
123
+ this.log('Skipping private kernel init proving...');
124
+ const proof = makeEmptyProof();
125
+
126
+ return {
127
+ publicInputs: result,
128
+ proof: proof,
129
+ };
130
+ }
131
+
132
+ public async createProofInner(privateInputs: PrivateKernelInputsInner): Promise<ProofOutput> {
133
+ const wasm = await CircuitsWasm.get();
134
+ const [time, result] = await elapsed(() => privateKernelSimInner(wasm, privateInputs));
135
+ if (result instanceof CircuitError) {
136
+ throw new CircuitError(result.code, result.message);
137
+ }
138
+ this.log(`Simulated private kernel inner`, {
139
+ eventName: 'circuit-simulation',
140
+ circuitName: 'private-kernel-inner',
141
+ duration: time.ms(),
142
+ inputSize: privateInputs.toBuffer().length,
143
+ outputSize: result.toBuffer().length,
144
+ });
145
+ this.log('Skipping private kernel inner proving...');
146
+ const proof = makeEmptyProof();
147
+
148
+ return {
149
+ publicInputs: result,
150
+ proof: proof,
151
+ };
152
+ }
153
+
154
+ public async createProofOrdering(privateInputs: PrivateKernelInputsOrdering): Promise<ProofOutputFinal> {
155
+ const wasm = await CircuitsWasm.get();
156
+ this.log('Executing private kernel simulation ordering...');
157
+ const [time, result] = await elapsed(() => privateKernelSimOrdering(wasm, privateInputs));
158
+ if (result instanceof CircuitError) {
159
+ throw new CircuitError(result.code, result.message);
160
+ }
161
+ this.log(`Simulated private kernel ordering`, {
162
+ eventName: 'circuit-simulation',
163
+ circuitName: 'private-kernel-ordering',
164
+ duration: time.ms(),
165
+ inputSize: privateInputs.toBuffer().length,
166
+ outputSize: result.toBuffer().length,
167
+ });
168
+ this.log('Skipping private kernel ordering proving...');
169
+ const proof = makeEmptyProof();
170
+
171
+ return {
172
+ publicInputs: result,
173
+ proof: proof,
174
+ };
175
+ }
176
+ }
@@ -0,0 +1,69 @@
1
+ import {
2
+ CONTRACT_TREE_HEIGHT,
3
+ FUNCTION_TREE_HEIGHT,
4
+ Fr,
5
+ FunctionSelector,
6
+ MembershipWitness,
7
+ PRIVATE_DATA_TREE_HEIGHT,
8
+ VK_TREE_HEIGHT,
9
+ VerificationKey,
10
+ } from '@aztec/circuits.js';
11
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
12
+
13
+ /**
14
+ * Provides functionality to fetch membership witnesses for verification keys,
15
+ * contract addresses, and function selectors in their respective merkle trees.
16
+ */
17
+ export interface ProvingDataOracle {
18
+ /**
19
+ * Retrieves the contract membership witness for a given contract address.
20
+ * A contract membership witness is a cryptographic proof that the contract exists in the Aztec network.
21
+ * This function will search for an existing contract tree associated with the contract address and obtain its
22
+ * membership witness. If no such contract tree exists, it will throw an error.
23
+ *
24
+ * @param contractAddress - The contract address.
25
+ * @returns A promise that resolves to a MembershipWitness instance representing the contract membership witness.
26
+ * @throws Error if the contract address is unknown or not found.
27
+ */
28
+ getContractMembershipWitness(contractAddress: AztecAddress): Promise<MembershipWitness<typeof CONTRACT_TREE_HEIGHT>>;
29
+
30
+ /**
31
+ * Retrieve the function membership witness for the given contract address and function selector.
32
+ * The function membership witness represents a proof that the function belongs to the specified contract.
33
+ * Throws an error if the contract address or function selector is unknown.
34
+ *
35
+ * @param contractAddress - The contract address.
36
+ * @param selector - The function selector.
37
+ * @returns A promise that resolves with the MembershipWitness instance for the specified contract's function.
38
+ */
39
+ getFunctionMembershipWitness(
40
+ contractAddress: AztecAddress,
41
+ selector: FunctionSelector,
42
+ ): Promise<MembershipWitness<typeof FUNCTION_TREE_HEIGHT>>;
43
+
44
+ /**
45
+ * Retrieve the membership witness corresponding to a verification key.
46
+ * This function currently returns a random membership witness of the specified height,
47
+ * which is a placeholder implementation until a concrete membership witness calculation
48
+ * is implemented.
49
+ *
50
+ * @param vk - The VerificationKey for which the membership witness is needed.
51
+ * @returns A Promise that resolves to the MembershipWitness instance.
52
+ */
53
+ getVkMembershipWitness(vk: VerificationKey): Promise<MembershipWitness<typeof VK_TREE_HEIGHT>>;
54
+
55
+ /**
56
+ * Get the note membership witness for a note in the private data tree at the given leaf index.
57
+ *
58
+ * @param leafIndex - The leaf index of the note in the private data tree.
59
+ * @returns the MembershipWitness for the note.
60
+ */
61
+ getNoteMembershipWitness(leafIndex: bigint): Promise<MembershipWitness<typeof PRIVATE_DATA_TREE_HEIGHT>>;
62
+
63
+ /**
64
+ * Get the root of the private data tree.
65
+ *
66
+ * @returns the root of the private data tree.
67
+ */
68
+ getPrivateDataRoot(): Promise<Fr>;
69
+ }
@@ -0,0 +1 @@
1
+ export * from './note_processor.js';
@@ -0,0 +1,267 @@
1
+ import { CircuitsWasm, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js';
2
+ import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis';
3
+ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
4
+ import { Fr } from '@aztec/foundation/fields';
5
+ import { createDebugLogger } from '@aztec/foundation/log';
6
+ import { AztecNode, KeyStore, L2BlockContext, L2BlockL2Logs, NoteSpendingInfo, PublicKey } from '@aztec/types';
7
+
8
+ import { Database, NoteSpendingInfoDao } from '../database/index.js';
9
+ import { getAcirSimulator } from '../simulator/index.js';
10
+
11
+ /**
12
+ * Contains all the decrypted data in this array so that we can later batch insert it all into the database.
13
+ */
14
+ interface ProcessedData {
15
+ /**
16
+ * Holds L2 block data and associated context.
17
+ */
18
+ blockContext: L2BlockContext;
19
+ /**
20
+ * A collection of data access objects for note spending info.
21
+ */
22
+ noteSpendingInfoDaos: NoteSpendingInfoDao[];
23
+ }
24
+
25
+ /**
26
+ * NoteProcessor is responsible for decrypting logs and converting them to notes via their originating contracts
27
+ * before storing them against their owner.
28
+ */
29
+ export class NoteProcessor {
30
+ /**
31
+ * The latest L2 block number that the note processor has synchronized to.
32
+ */
33
+ private syncedToBlock = 0;
34
+
35
+ constructor(
36
+ /**
37
+ * The public counterpart to the private key to be used in note decryption.
38
+ */
39
+ public readonly publicKey: PublicKey,
40
+ private keyStore: KeyStore,
41
+ private db: Database,
42
+ private node: AztecNode,
43
+ private simulator = getAcirSimulator(db, node, keyStore),
44
+ private log = createDebugLogger('aztec:aztec_note_processor'),
45
+ ) {}
46
+
47
+ /**
48
+ * Check if the NoteProcessor is synchronized with the remote block number.
49
+ * The function queries the remote block number from the AztecNode and compares it with the syncedToBlock value in the NoteProcessor.
50
+ * If the values are equal, then the NoteProcessor is considered to be synchronized, otherwise not.
51
+ *
52
+ * @returns A boolean indicating whether the NoteProcessor is synchronized with the remote block number or not.
53
+ */
54
+ public async isSynchronized() {
55
+ const remoteBlockNumber = await this.node.getBlockNumber();
56
+ return this.syncedToBlock === remoteBlockNumber;
57
+ }
58
+
59
+ /**
60
+ * Returns synchronisation status (ie up to which block has been synced ) for this note processor.
61
+ */
62
+ public get status() {
63
+ return { syncedToBlock: this.syncedToBlock };
64
+ }
65
+
66
+ /**
67
+ * Process the given L2 block contexts and encrypted logs to update the note processor.
68
+ * It synchronizes the user's account by decrypting the encrypted logs and processing
69
+ * the transactions and auxiliary data associated with them.
70
+ * Throws an error if the number of block contexts and encrypted logs do not match.
71
+ *
72
+ * @param l2BlockContexts - An array of L2 block contexts to be processed.
73
+ * @param encryptedL2BlockLogs - An array of encrypted logs associated with the L2 block contexts.
74
+ * @returns A promise that resolves once the processing is completed.
75
+ */
76
+ public async process(l2BlockContexts: L2BlockContext[], encryptedL2BlockLogs: L2BlockL2Logs[]): Promise<void> {
77
+ if (l2BlockContexts.length !== encryptedL2BlockLogs.length) {
78
+ throw new Error(
79
+ `Number of blocks and EncryptedLogs is not equal. Received ${l2BlockContexts.length} blocks, ${encryptedL2BlockLogs.length} encrypted logs.`,
80
+ );
81
+ }
82
+ if (!l2BlockContexts.length) {
83
+ return;
84
+ }
85
+
86
+ const blocksAndNoteSpendingInfo: ProcessedData[] = [];
87
+ const curve = await Grumpkin.new();
88
+
89
+ // Iterate over both blocks and encrypted logs.
90
+ for (let blockIndex = 0; blockIndex < encryptedL2BlockLogs.length; ++blockIndex) {
91
+ const { txLogs } = encryptedL2BlockLogs[blockIndex];
92
+ const block = l2BlockContexts[blockIndex].block;
93
+ const dataStartIndexForBlock = block.startPrivateDataTreeSnapshot.nextAvailableLeafIndex;
94
+
95
+ // We are using set for `userPertainingTxIndices` to avoid duplicates. This would happen in case there were
96
+ // multiple encrypted logs in a tx pertaining to a user.
97
+ const noteSpendingInfoDaos: NoteSpendingInfoDao[] = [];
98
+ const privateKey = await this.keyStore.getAccountPrivateKey(this.publicKey);
99
+
100
+ // Iterate over all the encrypted logs and try decrypting them. If successful, store the note spending info.
101
+ for (let indexOfTxInABlock = 0; indexOfTxInABlock < txLogs.length; ++indexOfTxInABlock) {
102
+ const dataStartIndexForTx = dataStartIndexForBlock + indexOfTxInABlock * MAX_NEW_COMMITMENTS_PER_TX;
103
+ const newCommitments = block.newCommitments.slice(
104
+ indexOfTxInABlock * MAX_NEW_COMMITMENTS_PER_TX,
105
+ (indexOfTxInABlock + 1) * MAX_NEW_COMMITMENTS_PER_TX,
106
+ );
107
+ const newNullifiers = block.newNullifiers.slice(
108
+ indexOfTxInABlock * MAX_NEW_NULLIFIERS_PER_TX,
109
+ (indexOfTxInABlock + 1) * MAX_NEW_NULLIFIERS_PER_TX,
110
+ );
111
+ // Note: Each tx generates a `TxL2Logs` object and for this reason we can rely on its index corresponding
112
+ // to the index of a tx in a block.
113
+ const txFunctionLogs = txLogs[indexOfTxInABlock].functionLogs;
114
+ const excludedIndices: Set<number> = new Set();
115
+ for (const functionLogs of txFunctionLogs) {
116
+ for (const logs of functionLogs.logs) {
117
+ const noteSpendingInfo = NoteSpendingInfo.fromEncryptedBuffer(logs, privateKey, curve);
118
+ if (noteSpendingInfo) {
119
+ // We have successfully decrypted the data.
120
+ try {
121
+ const { commitmentIndex, nonce, innerNoteHash, siloedNullifier } = await this.findNoteIndexAndNullifier(
122
+ newCommitments,
123
+ newNullifiers[0],
124
+ noteSpendingInfo,
125
+ excludedIndices,
126
+ );
127
+ const index = BigInt(dataStartIndexForTx + commitmentIndex);
128
+ excludedIndices.add(commitmentIndex);
129
+ noteSpendingInfoDaos.push({
130
+ ...noteSpendingInfo,
131
+ nonce,
132
+ innerNoteHash,
133
+ siloedNullifier,
134
+ index,
135
+ publicKey: this.publicKey,
136
+ });
137
+ } catch (e) {
138
+ this.log.warn(`Could not process note because of "${e}". Skipping note...`);
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ blocksAndNoteSpendingInfo.push({
146
+ blockContext: l2BlockContexts[blockIndex],
147
+ noteSpendingInfoDaos,
148
+ });
149
+ }
150
+
151
+ await this.processBlocksAndNoteSpendingInfo(blocksAndNoteSpendingInfo);
152
+
153
+ this.syncedToBlock = l2BlockContexts[l2BlockContexts.length - 1].block.number;
154
+ this.log(`Synched block ${this.syncedToBlock}`);
155
+ }
156
+
157
+ /**
158
+ * Find the index of the note in the private data tree by computing the note hash with different nonce and see which
159
+ * commitment for the current tx matches this value.
160
+ * Compute the nullifier for a given transaction auxiliary data.
161
+ * The nullifier is calculated using the private key of the account,
162
+ * contract address, and note preimage associated with the noteSpendingInfo.
163
+ * This method assists in identifying spent commitments in the private state.
164
+ * @param commitments - Commitments in the tx. One of them should be the note's commitment.
165
+ * @param firstNullifier - First nullifier in the tx.
166
+ * @param noteSpendingInfo - An instance of NoteSpendingInfo containing transaction details.
167
+ * @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
168
+ * NoteSpendingInfo. We need to find a different index for each replicate.
169
+ * @returns Information for a decrypted note, including the index of its commitment, nonce, inner note
170
+ * hash, and the siloed nullifier. Throw if cannot find the nonce for the note.
171
+ */
172
+ private async findNoteIndexAndNullifier(
173
+ commitments: Fr[],
174
+ firstNullifier: Fr,
175
+ { contractAddress, storageSlot, notePreimage }: NoteSpendingInfo,
176
+ excludedIndices: Set<number>,
177
+ ) {
178
+ const wasm = await CircuitsWasm.get();
179
+ let commitmentIndex = 0;
180
+ let nonce: Fr | undefined;
181
+ let innerNoteHash: Fr | undefined;
182
+ let siloedNoteHash: Fr | undefined;
183
+ let uniqueSiloedNoteHash: Fr | undefined;
184
+ let innerNullifier: Fr | undefined;
185
+ for (; commitmentIndex < commitments.length; ++commitmentIndex) {
186
+ if (excludedIndices.has(commitmentIndex)) continue;
187
+
188
+ const commitment = commitments[commitmentIndex];
189
+ if (commitment.equals(Fr.ZERO)) break;
190
+
191
+ const expectedNonce = computeCommitmentNonce(wasm, firstNullifier, commitmentIndex);
192
+ ({ innerNoteHash, siloedNoteHash, uniqueSiloedNoteHash, innerNullifier } =
193
+ await this.simulator.computeNoteHashAndNullifier(
194
+ contractAddress,
195
+ expectedNonce,
196
+ storageSlot,
197
+ notePreimage.items,
198
+ ));
199
+ if (commitment.equals(uniqueSiloedNoteHash)) {
200
+ nonce = expectedNonce;
201
+ break;
202
+ }
203
+ }
204
+
205
+ if (!nonce) {
206
+ let errorString;
207
+ if (siloedNoteHash == undefined) {
208
+ errorString = 'Cannot find a matching commitment for the note.';
209
+ } else {
210
+ errorString = `We decrypted a log, but couldn't find a corresponding note in the tree.
211
+ This might be because the note was nullified in the same tx which created it.
212
+ In that case, everything is fine. To check whether this is the case, look back through
213
+ the logs for a notification
214
+ 'important: chopped commitment for siloed inner hash note
215
+ ${siloedNoteHash.toString()}'.
216
+ If you can see that notification. Everything's fine.
217
+ If that's not the case, and you can't find such a notification, something has gone wrong.
218
+ There could be a problem with the way you've defined a custom note, or with the way you're
219
+ serialising / deserialising / hashing / encrypting / decrypting that note.
220
+ Please see the following github issue to track an improvement that we're working on:
221
+ https://github.com/AztecProtocol/aztec-packages/issues/1641`;
222
+ }
223
+
224
+ throw new Error(errorString);
225
+ }
226
+
227
+ return {
228
+ commitmentIndex,
229
+ nonce,
230
+ innerNoteHash: innerNoteHash!,
231
+ siloedNullifier: siloNullifier(wasm, contractAddress, innerNullifier!),
232
+ };
233
+ }
234
+
235
+ /**
236
+ * Process the given blocks and their associated transaction auxiliary data.
237
+ * This function updates the database with information about new transactions,
238
+ * user-pertaining transaction indices, and auxiliary data. It also removes nullified
239
+ * transaction auxiliary data from the database. This function keeps track of new nullifiers
240
+ * and ensures all other transactions are updated with newly settled block information.
241
+ *
242
+ * @param blocksAndNoteSpendingInfo - Array of objects containing L2BlockContexts, user-pertaining transaction indices, and NoteSpendingInfoDaos.
243
+ */
244
+ private async processBlocksAndNoteSpendingInfo(blocksAndNoteSpendingInfo: ProcessedData[]) {
245
+ const noteSpendingInfoDaosBatch = blocksAndNoteSpendingInfo.flatMap(b => b.noteSpendingInfoDaos);
246
+ if (noteSpendingInfoDaosBatch.length) {
247
+ await this.db.addNoteSpendingInfoBatch(noteSpendingInfoDaosBatch);
248
+ noteSpendingInfoDaosBatch.forEach(noteSpendingInfo => {
249
+ this.log(
250
+ `Added note spending info for contract ${noteSpendingInfo.contractAddress} at slot ${
251
+ noteSpendingInfo.storageSlot
252
+ } with nullifier ${noteSpendingInfo.siloedNullifier.toString()}`,
253
+ );
254
+ });
255
+ }
256
+
257
+ const newNullifiers: Fr[] = blocksAndNoteSpendingInfo.flatMap(b => b.blockContext.block.newNullifiers);
258
+ const removedNoteSpendingInfo = await this.db.removeNullifiedNoteSpendingInfo(newNullifiers, this.publicKey);
259
+ removedNoteSpendingInfo.forEach(noteSpendingInfo => {
260
+ this.log(
261
+ `Removed note spending info for contract ${noteSpendingInfo.contractAddress} at slot ${
262
+ noteSpendingInfo.storageSlot
263
+ } with nullifier ${noteSpendingInfo.siloedNullifier.toString()}`,
264
+ );
265
+ });
266
+ }
267
+ }
@@ -0,0 +1 @@
1
+ export * from './pxe_http_server.js';
@@ -0,0 +1,70 @@
1
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
2
+ import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields';
3
+ import { JsonRpcServer } from '@aztec/foundation/json-rpc/server';
4
+ import {
5
+ AuthWitness,
6
+ CompleteAddress,
7
+ ContractData,
8
+ ExtendedContractData,
9
+ L2Block,
10
+ L2BlockL2Logs,
11
+ L2Tx,
12
+ NotePreimage,
13
+ PXE,
14
+ Tx,
15
+ TxExecutionRequest,
16
+ TxHash,
17
+ TxReceipt,
18
+ } from '@aztec/types';
19
+
20
+ import http from 'http';
21
+ import { foundry } from 'viem/chains';
22
+
23
+ import { EthAddress } from '../index.js';
24
+
25
+ export const localAnvil = foundry;
26
+
27
+ /**
28
+ * Wraps an instance of Private eXecution Environment (PXE) implementation to a JSON RPC HTTP interface.
29
+ * @returns A new instance of the HTTP server.
30
+ */
31
+ export function createPXERpcServer(pxeService: PXE): JsonRpcServer {
32
+ return new JsonRpcServer(
33
+ pxeService,
34
+ {
35
+ CompleteAddress,
36
+ AztecAddress,
37
+ TxExecutionRequest,
38
+ ContractData,
39
+ ExtendedContractData,
40
+ TxHash,
41
+ EthAddress,
42
+ Point,
43
+ Fr,
44
+ GrumpkinScalar,
45
+ NotePreimage,
46
+ AuthWitness,
47
+ L2Block,
48
+ L2Tx,
49
+ },
50
+ { Tx, TxReceipt, L2BlockL2Logs },
51
+ false,
52
+ ['start', 'stop'],
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Creates an http server that forwards calls to the PXE and starts it on the given port.
58
+ * @param pxeService - PXE that answers queries to the created HTTP server.
59
+ * @param port - Port to listen in.
60
+ * @returns A running http server.
61
+ */
62
+ export function startPXEHttpServer(pxeService: PXE, port: string | number): http.Server {
63
+ const rpcServer = createPXERpcServer(pxeService);
64
+
65
+ const app = rpcServer.getApp();
66
+ const httpServer = http.createServer(app.callback());
67
+ httpServer.listen(port);
68
+
69
+ return httpServer;
70
+ }
@@ -0,0 +1,52 @@
1
+ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
2
+ import { TestKeyStore } from '@aztec/key-store';
3
+ import { AztecNode, KeyStore } from '@aztec/types';
4
+
5
+ import { PXEServiceConfig } from '../config/index.js';
6
+ import { Database, MemoryDB } from '../database/index.js';
7
+ import { PXEService } from './pxe_service.js';
8
+
9
+ /**
10
+ * Optional information for creating an PXEService.
11
+ */
12
+ interface CreatePXEServiceOptions {
13
+ /**
14
+ * A secure storage for cryptographic keys.
15
+ */
16
+ keyStore?: KeyStore;
17
+ /**
18
+ * Storage for the PXE.
19
+ */
20
+ db?: Database;
21
+ }
22
+
23
+ /**
24
+ * Create and start an PXEService instance with the given AztecNode.
25
+ * If no keyStore or database is provided, it will use TestKeyStore and MemoryDB as default values.
26
+ * Returns a Promise that resolves to the started PXEService instance.
27
+ *
28
+ * @param aztecNode - The AztecNode instance to be used by the server.
29
+ * @param config - The PXE Service Config to use
30
+ * @param options - (Optional) Optional information for creating an PXEService.
31
+ * @returns A Promise that resolves to the started PXEService instance.
32
+ */
33
+ export async function createPXEService(
34
+ aztecNode: AztecNode,
35
+ config: PXEServiceConfig,
36
+ { keyStore, db }: CreatePXEServiceOptions = {},
37
+ useLogSuffix: string | boolean | undefined = undefined,
38
+ ) {
39
+ const logSuffix =
40
+ typeof useLogSuffix === 'boolean'
41
+ ? useLogSuffix
42
+ ? Math.random().toString(16).slice(2, 8)
43
+ : undefined
44
+ : useLogSuffix;
45
+
46
+ keyStore = keyStore || new TestKeyStore(await Grumpkin.new());
47
+ db = db || new MemoryDB(logSuffix);
48
+
49
+ const server = new PXEService(keyStore, aztecNode, db, config, logSuffix);
50
+ await server.start();
51
+ return server;
52
+ }
@@ -0,0 +1,3 @@
1
+ export * from './pxe_service.js';
2
+ export * from './create_pxe_service.js';
3
+ export { pxeTestSuite } from './test/pxe_test_suite.js';