@aztec/pxe 0.23.0 → 0.26.1

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 (76) hide show
  1. package/dest/config/index.js +2 -2
  2. package/dest/database/deferred_note_dao.d.ts +8 -4
  3. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  4. package/dest/database/deferred_note_dao.js +9 -6
  5. package/dest/database/note_dao.d.ts +4 -0
  6. package/dest/database/note_dao.d.ts.map +1 -1
  7. package/dest/database/note_dao.js +7 -2
  8. package/dest/database/pxe_database_test_suite.js +5 -5
  9. package/dest/kernel_oracle/index.d.ts +1 -0
  10. package/dest/kernel_oracle/index.d.ts.map +1 -1
  11. package/dest/kernel_oracle/index.js +4 -1
  12. package/dest/kernel_prover/hints_builder.d.ts +36 -0
  13. package/dest/kernel_prover/hints_builder.d.ts.map +1 -0
  14. package/dest/kernel_prover/hints_builder.js +115 -0
  15. package/dest/kernel_prover/kernel_prover.d.ts +2 -24
  16. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  17. package/dest/kernel_prover/kernel_prover.js +32 -103
  18. package/dest/kernel_prover/proof_creator.d.ts +11 -11
  19. package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
  20. package/dest/kernel_prover/proof_creator.js +6 -6
  21. package/dest/kernel_prover/proving_data_oracle.d.ts +2 -0
  22. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -1
  23. package/dest/note_processor/note_processor.d.ts.map +1 -1
  24. package/dest/note_processor/note_processor.js +15 -14
  25. package/dest/note_processor/produce_note_dao.d.ts +2 -2
  26. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  27. package/dest/note_processor/produce_note_dao.js +8 -8
  28. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
  29. package/dest/pxe_http/pxe_http_server.js +7 -6
  30. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  31. package/dest/pxe_service/create_pxe_service.js +5 -1
  32. package/dest/pxe_service/pxe_service.d.ts +5 -3
  33. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  34. package/dest/pxe_service/pxe_service.js +51 -44
  35. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
  36. package/dest/pxe_service/test/pxe_test_suite.js +3 -3
  37. package/dest/simulator_oracle/index.d.ts +7 -4
  38. package/dest/simulator_oracle/index.d.ts.map +1 -1
  39. package/dest/simulator_oracle/index.js +17 -8
  40. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  41. package/dest/synchronizer/synchronizer.js +14 -42
  42. package/package.json +14 -13
  43. package/src/bin/index.ts +42 -0
  44. package/src/config/index.ts +40 -0
  45. package/src/contract_data_oracle/index.ts +185 -0
  46. package/src/contract_data_oracle/private_functions_tree.ts +127 -0
  47. package/src/contract_database/index.ts +1 -0
  48. package/src/contract_database/memory_contract_database.ts +58 -0
  49. package/src/database/contracts/contract_artifact_db.ts +19 -0
  50. package/src/database/contracts/contract_instance_db.ts +18 -0
  51. package/src/database/deferred_note_dao.ts +55 -0
  52. package/src/database/index.ts +1 -0
  53. package/src/database/kv_pxe_database.ts +409 -0
  54. package/src/database/note_dao.ts +97 -0
  55. package/src/database/pxe_database.ts +162 -0
  56. package/src/database/pxe_database_test_suite.ts +258 -0
  57. package/src/index.ts +11 -0
  58. package/src/kernel_oracle/index.ts +65 -0
  59. package/src/kernel_prover/hints_builder.ts +170 -0
  60. package/src/kernel_prover/index.ts +2 -0
  61. package/src/kernel_prover/kernel_prover.ts +309 -0
  62. package/src/kernel_prover/proof_creator.ts +157 -0
  63. package/src/kernel_prover/proving_data_oracle.ts +79 -0
  64. package/src/note_processor/index.ts +1 -0
  65. package/src/note_processor/note_processor.ts +275 -0
  66. package/src/note_processor/produce_note_dao.ts +132 -0
  67. package/src/pxe_http/index.ts +1 -0
  68. package/src/pxe_http/pxe_http_server.ts +75 -0
  69. package/src/pxe_service/create_pxe_service.ts +53 -0
  70. package/src/pxe_service/index.ts +3 -0
  71. package/src/pxe_service/pxe_service.ts +769 -0
  72. package/src/pxe_service/test/pxe_test_suite.ts +140 -0
  73. package/src/simulator/index.ts +24 -0
  74. package/src/simulator_oracle/index.ts +222 -0
  75. package/src/synchronizer/index.ts +1 -0
  76. package/src/synchronizer/synchronizer.ts +385 -0
@@ -0,0 +1,275 @@
1
+ import { AztecNode, KeyStore, L1NotePayload, L2BlockContext, L2BlockL2Logs, TaggedNote } from '@aztec/circuit-types';
2
+ import { NoteProcessorStats } from '@aztec/circuit-types/stats';
3
+ import { INITIAL_L2_BLOCK_NUM, MAX_NEW_NOTE_HASHES_PER_TX, PublicKey } from '@aztec/circuits.js';
4
+ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
5
+ import { Fr } from '@aztec/foundation/fields';
6
+ import { createDebugLogger } from '@aztec/foundation/log';
7
+ import { Timer } from '@aztec/foundation/timer';
8
+ import { ContractNotFoundError } from '@aztec/simulator';
9
+
10
+ import { DeferredNoteDao } from '../database/deferred_note_dao.js';
11
+ import { PxeDatabase } from '../database/index.js';
12
+ import { NoteDao } from '../database/note_dao.js';
13
+ import { getAcirSimulator } from '../simulator/index.js';
14
+ import { produceNoteDao } from './produce_note_dao.js';
15
+
16
+ /**
17
+ * Contains all the decrypted data in this array so that we can later batch insert it all into the database.
18
+ */
19
+ interface ProcessedData {
20
+ /**
21
+ * Holds L2 block and a cache of already requested tx hashes.
22
+ */
23
+ blockContext: L2BlockContext;
24
+ /**
25
+ * DAOs of processed notes.
26
+ */
27
+ noteDaos: NoteDao[];
28
+ }
29
+
30
+ /**
31
+ * NoteProcessor is responsible for decrypting logs and converting them to notes via their originating contracts
32
+ * before storing them against their owner.
33
+ */
34
+ export class NoteProcessor {
35
+ /** Keeps track of processing time since an instance is created. */
36
+ public readonly timer: Timer = new Timer();
37
+
38
+ /** Stats accumulated for this processor. */
39
+ public readonly stats: NoteProcessorStats = { seen: 0, decrypted: 0, deferred: 0, failed: 0, blocks: 0, txs: 0 };
40
+
41
+ constructor(
42
+ /**
43
+ * The public counterpart to the private key to be used in note decryption.
44
+ */
45
+ public readonly publicKey: PublicKey,
46
+ private keyStore: KeyStore,
47
+ private db: PxeDatabase,
48
+ private node: AztecNode,
49
+ private startingBlock: number = INITIAL_L2_BLOCK_NUM,
50
+ private simulator = getAcirSimulator(db, node, keyStore),
51
+ private log = createDebugLogger('aztec:note_processor'),
52
+ ) {}
53
+
54
+ /**
55
+ * Check if the NoteProcessor is synchronized with the remote block number.
56
+ * The function queries the remote block number from the AztecNode and compares it with the syncedToBlock value in the NoteProcessor.
57
+ * If the values are equal, then the NoteProcessor is considered to be synchronized, otherwise not.
58
+ *
59
+ * @returns A boolean indicating whether the NoteProcessor is synchronized with the remote block number or not.
60
+ */
61
+ public async isSynchronized() {
62
+ const remoteBlockNumber = await this.node.getBlockNumber();
63
+ return this.getSyncedToBlock() === remoteBlockNumber;
64
+ }
65
+
66
+ /**
67
+ * Returns synchronization status (ie up to which block has been synced ) for this note processor.
68
+ */
69
+ public get status() {
70
+ return { syncedToBlock: this.getSyncedToBlock() };
71
+ }
72
+
73
+ private getSyncedToBlock(): number {
74
+ return this.db.getSynchedBlockNumberForPublicKey(this.publicKey) ?? this.startingBlock - 1;
75
+ }
76
+
77
+ /**
78
+ * Process the given L2 block contexts and encrypted logs to update the note processor.
79
+ * It synchronizes the user's account by decrypting the encrypted logs and processing
80
+ * the transactions and auxiliary data associated with them.
81
+ * Throws an error if the number of block contexts and encrypted logs do not match.
82
+ *
83
+ * @param l2BlockContexts - An array of L2 block contexts to be processed.
84
+ * @param encryptedL2BlockLogs - An array of encrypted logs associated with the L2 block contexts.
85
+ * @returns A promise that resolves once the processing is completed.
86
+ */
87
+ public async process(l2BlockContexts: L2BlockContext[], encryptedL2BlockLogs: L2BlockL2Logs[]): Promise<void> {
88
+ if (l2BlockContexts.length !== encryptedL2BlockLogs.length) {
89
+ throw new Error(
90
+ `Number of blocks and EncryptedLogs is not equal. Received ${l2BlockContexts.length} blocks, ${encryptedL2BlockLogs.length} encrypted logs.`,
91
+ );
92
+ }
93
+ if (!l2BlockContexts.length) {
94
+ return;
95
+ }
96
+
97
+ const curve = new Grumpkin();
98
+ const blocksAndNotes: ProcessedData[] = [];
99
+ // Keep track of notes that we couldn't process because the contract was not found.
100
+ const deferredNoteDaos: DeferredNoteDao[] = [];
101
+
102
+ // Iterate over both blocks and encrypted logs.
103
+ for (let blockIndex = 0; blockIndex < encryptedL2BlockLogs.length; ++blockIndex) {
104
+ this.stats.blocks++;
105
+ const { txLogs } = encryptedL2BlockLogs[blockIndex];
106
+ const blockContext = l2BlockContexts[blockIndex];
107
+ const block = blockContext.block;
108
+ const dataEndIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex;
109
+
110
+ // We are using set for `userPertainingTxIndices` to avoid duplicates. This would happen in case there were
111
+ // multiple encrypted logs in a tx pertaining to a user.
112
+ const noteDaos: NoteDao[] = [];
113
+ const privateKey = await this.keyStore.getAccountPrivateKey(this.publicKey);
114
+
115
+ // Iterate over all the encrypted logs and try decrypting them. If successful, store the note.
116
+ for (let indexOfTxInABlock = 0; indexOfTxInABlock < txLogs.length; ++indexOfTxInABlock) {
117
+ this.stats.txs++;
118
+ const dataStartIndexForTx =
119
+ dataEndIndexForBlock - (txLogs.length - indexOfTxInABlock) * MAX_NEW_NOTE_HASHES_PER_TX;
120
+ const newNoteHashes = block.body.txEffects[indexOfTxInABlock].noteHashes;
121
+ // Note: Each tx generates a `TxL2Logs` object and for this reason we can rely on its index corresponding
122
+ // to the index of a tx in a block.
123
+ const txFunctionLogs = txLogs[indexOfTxInABlock].functionLogs;
124
+ const excludedIndices: Set<number> = new Set();
125
+ for (const functionLogs of txFunctionLogs) {
126
+ for (const log of functionLogs.logs) {
127
+ this.stats.seen++;
128
+ const taggedNote = TaggedNote.fromEncryptedBuffer(log, privateKey, curve);
129
+ if (taggedNote?.notePayload) {
130
+ const { notePayload: payload } = taggedNote;
131
+ // We have successfully decrypted the data.
132
+ const txHash = blockContext.getTxHash(indexOfTxInABlock);
133
+ try {
134
+ const noteDao = await produceNoteDao(
135
+ this.simulator,
136
+ this.publicKey,
137
+ payload,
138
+ txHash,
139
+ newNoteHashes,
140
+ dataStartIndexForTx,
141
+ excludedIndices,
142
+ );
143
+ noteDaos.push(noteDao);
144
+ this.stats.decrypted++;
145
+ } catch (e) {
146
+ if (e instanceof ContractNotFoundError) {
147
+ this.stats.deferred++;
148
+ this.log.warn(e.message);
149
+ const deferredNoteDao = new DeferredNoteDao(
150
+ this.publicKey,
151
+ payload.note,
152
+ payload.contractAddress,
153
+ payload.storageSlot,
154
+ payload.noteTypeId,
155
+ txHash,
156
+ newNoteHashes,
157
+ dataStartIndexForTx,
158
+ );
159
+ deferredNoteDaos.push(deferredNoteDao);
160
+ } else {
161
+ this.stats.failed++;
162
+ this.log.warn(`Could not process note because of "${e}". Discarding note...`);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+
170
+ blocksAndNotes.push({
171
+ blockContext: l2BlockContexts[blockIndex],
172
+ noteDaos,
173
+ });
174
+ }
175
+
176
+ await this.processBlocksAndNotes(blocksAndNotes);
177
+ await this.processDeferredNotes(deferredNoteDaos);
178
+
179
+ const syncedToBlock = l2BlockContexts[l2BlockContexts.length - 1].block.number;
180
+ await this.db.setSynchedBlockNumberForPublicKey(this.publicKey, syncedToBlock);
181
+
182
+ this.log(`Synched block ${syncedToBlock}`);
183
+ }
184
+
185
+ /**
186
+ * Process the given blocks and their associated transaction auxiliary data.
187
+ * This function updates the database with information about new transactions,
188
+ * user-pertaining transaction indices, and auxiliary data. It also removes nullified
189
+ * transaction auxiliary data from the database. This function keeps track of new nullifiers
190
+ * and ensures all other transactions are updated with newly settled block information.
191
+ *
192
+ * @param blocksAndNotes - Array of objects containing L2BlockContexts, user-pertaining transaction indices, and NoteDaos.
193
+ */
194
+ private async processBlocksAndNotes(blocksAndNotes: ProcessedData[]) {
195
+ const noteDaos = blocksAndNotes.flatMap(b => b.noteDaos);
196
+ if (noteDaos.length) {
197
+ await this.db.addNotes(noteDaos);
198
+ noteDaos.forEach(noteDao => {
199
+ this.log(
200
+ `Added note for contract ${noteDao.contractAddress} at slot ${
201
+ noteDao.storageSlot
202
+ } with nullifier ${noteDao.siloedNullifier.toString()}`,
203
+ );
204
+ });
205
+ }
206
+
207
+ const newNullifiers: Fr[] = blocksAndNotes.flatMap(b =>
208
+ b.blockContext.block.body.txEffects.flatMap(txEffect => txEffect.nullifiers),
209
+ );
210
+ const removedNotes = await this.db.removeNullifiedNotes(newNullifiers, this.publicKey);
211
+ removedNotes.forEach(noteDao => {
212
+ this.log(
213
+ `Removed note for contract ${noteDao.contractAddress} at slot ${
214
+ noteDao.storageSlot
215
+ } with nullifier ${noteDao.siloedNullifier.toString()}`,
216
+ );
217
+ });
218
+ }
219
+
220
+ /**
221
+ * Store the given deferred notes in the database for later decoding.
222
+ *
223
+ * @param deferredNoteDaos - notes that are intended for us but we couldn't process because the contract was not found.
224
+ */
225
+ private async processDeferredNotes(deferredNoteDaos: DeferredNoteDao[]) {
226
+ if (deferredNoteDaos.length) {
227
+ await this.db.addDeferredNotes(deferredNoteDaos);
228
+ deferredNoteDaos.forEach(noteDao => {
229
+ this.log(
230
+ `Deferred note for contract ${noteDao.contractAddress} at slot ${
231
+ noteDao.storageSlot
232
+ } in tx ${noteDao.txHash.toString()}`,
233
+ );
234
+ });
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Retry decoding the given deferred notes because we now have the contract code.
240
+ *
241
+ * @param deferredNoteDaos - notes that we have previously deferred because the contract was not found
242
+ * @returns An array of NoteDaos that were successfully decoded.
243
+ *
244
+ * @remarks Caller is responsible for making sure that we have the contract for the
245
+ * deferred notes provided: we will not retry notes that fail again.
246
+ */
247
+ public async decodeDeferredNotes(deferredNoteDaos: DeferredNoteDao[]): Promise<NoteDao[]> {
248
+ const excludedIndices: Set<number> = new Set();
249
+ const noteDaos: NoteDao[] = [];
250
+ for (const deferredNote of deferredNoteDaos) {
251
+ const { note, contractAddress, storageSlot, noteTypeId, txHash, newNoteHashes, dataStartIndexForTx } =
252
+ deferredNote;
253
+ const payload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
254
+
255
+ try {
256
+ const noteDao = await produceNoteDao(
257
+ this.simulator,
258
+ this.publicKey,
259
+ payload,
260
+ txHash,
261
+ newNoteHashes,
262
+ dataStartIndexForTx,
263
+ excludedIndices,
264
+ );
265
+ noteDaos.push(noteDao);
266
+ this.stats.decrypted++;
267
+ } catch (e) {
268
+ this.stats.failed++;
269
+ this.log.warn(`Could not process deferred note because of "${e}". Discarding note...`);
270
+ }
271
+ }
272
+
273
+ return noteDaos;
274
+ }
275
+ }
@@ -0,0 +1,132 @@
1
+ import { L1NotePayload, TxHash } from '@aztec/circuit-types';
2
+ import { Fr, PublicKey } from '@aztec/circuits.js';
3
+ import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/hash';
4
+ import { AcirSimulator } from '@aztec/simulator';
5
+
6
+ import { NoteDao } from '../database/note_dao.js';
7
+
8
+ /**
9
+ * Decodes a note from a transaction that we know was intended for us.
10
+ * Throws if we do not yet have the contract corresponding to the note in our database.
11
+ * Accepts a set of excluded indices, which are indices that have been assigned a note in the same tx.
12
+ * Inserts the index of the note into the excludedIndices set if the note is successfully decoded.
13
+ *
14
+ * @param publicKey - The public counterpart to the private key to be used in note decryption.
15
+ * @param payload - An instance of l1NotePayload.
16
+ * @param txHash - The hash of the transaction that created the note. Equivalent to the first nullifier of the transaction.
17
+ * @param newNoteHashes - New note hashes in this transaction, one of which belongs to this note.
18
+ * @param dataStartIndexForTx - The next available leaf index for the note hash tree for this transaction.
19
+ * @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same l1NotePayload, we need to find a different index for each replicate.
20
+ * @param simulator - An instance of AcirSimulator.
21
+ * @returns an instance of NoteDao, or throws. inserts the index of the note into the excludedIndices set.
22
+ */
23
+ export async function produceNoteDao(
24
+ simulator: AcirSimulator,
25
+ publicKey: PublicKey,
26
+ payload: L1NotePayload,
27
+ txHash: TxHash,
28
+ newNoteHashes: Fr[],
29
+ dataStartIndexForTx: number,
30
+ excludedIndices: Set<number>,
31
+ ): Promise<NoteDao> {
32
+ const { commitmentIndex, nonce, innerNoteHash, siloedNullifier } = await findNoteIndexAndNullifier(
33
+ simulator,
34
+ newNoteHashes,
35
+ txHash,
36
+ payload,
37
+ excludedIndices,
38
+ );
39
+ const index = BigInt(dataStartIndexForTx + commitmentIndex);
40
+ excludedIndices?.add(commitmentIndex);
41
+ return new NoteDao(
42
+ payload.note,
43
+ payload.contractAddress,
44
+ payload.storageSlot,
45
+ payload.noteTypeId,
46
+ txHash,
47
+ nonce,
48
+ innerNoteHash,
49
+ siloedNullifier,
50
+ index,
51
+ publicKey,
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Find the index of the note in the note hash tree by computing the note hash with different nonce and see which
57
+ * commitment for the current tx matches this value.
58
+ * Compute a nullifier for a given l1NotePayload.
59
+ * The nullifier is calculated using the private key of the account,
60
+ * contract address, and the note associated with the l1NotePayload.
61
+ * This method assists in identifying spent commitments in the private state.
62
+ * @param commitments - Commitments in the tx. One of them should be the note's commitment.
63
+ * @param txHash - First nullifier in the tx.
64
+ * @param l1NotePayload - An instance of l1NotePayload.
65
+ * @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
66
+ * l1NotePayload. We need to find a different index for each replicate.
67
+ * @returns Information for a decrypted note, including the index of its commitment, nonce, inner note
68
+ * hash, and the siloed nullifier. Throw if cannot find the nonce for the note.
69
+ */
70
+ async function findNoteIndexAndNullifier(
71
+ simulator: AcirSimulator,
72
+ commitments: Fr[],
73
+ txHash: TxHash,
74
+ { contractAddress, storageSlot, noteTypeId, note }: L1NotePayload,
75
+ excludedIndices: Set<number>,
76
+ ) {
77
+ let commitmentIndex = 0;
78
+ let nonce: Fr | undefined;
79
+ let innerNoteHash: Fr | undefined;
80
+ let siloedNoteHash: Fr | undefined;
81
+ let uniqueSiloedNoteHash: Fr | undefined;
82
+ let innerNullifier: Fr | undefined;
83
+ const firstNullifier = Fr.fromBuffer(txHash.toBuffer());
84
+
85
+ for (; commitmentIndex < commitments.length; ++commitmentIndex) {
86
+ if (excludedIndices.has(commitmentIndex)) {
87
+ continue;
88
+ }
89
+
90
+ const commitment = commitments[commitmentIndex];
91
+ if (commitment.equals(Fr.ZERO)) {
92
+ break;
93
+ }
94
+
95
+ const expectedNonce = computeCommitmentNonce(firstNullifier, commitmentIndex);
96
+ ({ innerNoteHash, siloedNoteHash, uniqueSiloedNoteHash, innerNullifier } =
97
+ await simulator.computeNoteHashAndNullifier(contractAddress, expectedNonce, storageSlot, noteTypeId, note));
98
+ if (commitment.equals(uniqueSiloedNoteHash)) {
99
+ nonce = expectedNonce;
100
+ break;
101
+ }
102
+ }
103
+
104
+ if (!nonce) {
105
+ let errorString;
106
+ if (siloedNoteHash == undefined) {
107
+ errorString = 'Cannot find a matching commitment for the note.';
108
+ } else {
109
+ errorString = `We decrypted a log, but couldn't find a corresponding note in the tree.
110
+ This might be because the note was nullified in the same tx which created it.
111
+ In that case, everything is fine. To check whether this is the case, look back through
112
+ the logs for a notification
113
+ 'important: chopped commitment for siloed inner hash note
114
+ ${siloedNoteHash.toString()}'.
115
+ If you can see that notification. Everything's fine.
116
+ If that's not the case, and you can't find such a notification, something has gone wrong.
117
+ There could be a problem with the way you've defined a custom note, or with the way you're
118
+ serializing / deserializing / hashing / encrypting / decrypting that note.
119
+ Please see the following github issue to track an improvement that we're working on:
120
+ https://github.com/AztecProtocol/aztec-packages/issues/1641`;
121
+ }
122
+
123
+ throw new Error(errorString);
124
+ }
125
+
126
+ return {
127
+ commitmentIndex,
128
+ nonce,
129
+ innerNoteHash: innerNoteHash!,
130
+ siloedNullifier: siloNullifier(contractAddress, innerNullifier!),
131
+ };
132
+ }
@@ -0,0 +1 @@
1
+ export * from './pxe_http_server.js';
@@ -0,0 +1,75 @@
1
+ import {
2
+ AuthWitness,
3
+ CompleteAddress,
4
+ ContractData,
5
+ ExtendedContractData,
6
+ ExtendedNote,
7
+ ExtendedUnencryptedL2Log,
8
+ L2Block,
9
+ L2BlockL2Logs,
10
+ LogId,
11
+ Note,
12
+ NullifierMembershipWitness,
13
+ PXE,
14
+ Tx,
15
+ TxEffect,
16
+ TxExecutionRequest,
17
+ TxHash,
18
+ TxReceipt,
19
+ } from '@aztec/circuit-types';
20
+ import { FunctionSelector } from '@aztec/circuits.js';
21
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
22
+ import { EthAddress } from '@aztec/foundation/eth-address';
23
+ import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields';
24
+ import { JsonRpcServer, createNamespacedJsonRpcServer } from '@aztec/foundation/json-rpc/server';
25
+
26
+ import http from 'http';
27
+
28
+ /**
29
+ * Wraps an instance of Private eXecution Environment (PXE) implementation to a JSON RPC HTTP interface.
30
+ * @returns A new instance of the HTTP server.
31
+ */
32
+ export function createPXERpcServer(pxeService: PXE): JsonRpcServer {
33
+ return new JsonRpcServer(
34
+ pxeService,
35
+ {
36
+ CompleteAddress,
37
+ AztecAddress,
38
+ TxExecutionRequest,
39
+ ContractData,
40
+ ExtendedContractData,
41
+ ExtendedUnencryptedL2Log,
42
+ FunctionSelector,
43
+ TxHash,
44
+ EthAddress,
45
+ Point,
46
+ Fr,
47
+ GrumpkinScalar,
48
+ Note,
49
+ ExtendedNote,
50
+ AuthWitness,
51
+ L2Block,
52
+ TxEffect,
53
+ LogId,
54
+ },
55
+ { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness },
56
+ ['start', 'stop'],
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Creates an http server that forwards calls to the PXE and starts it on the given port.
62
+ * @param pxeService - PXE that answers queries to the created HTTP server.
63
+ * @param port - Port to listen in.
64
+ * @returns A running http server.
65
+ */
66
+ export function startPXEHttpServer(pxeService: PXE, port: string | number): http.Server {
67
+ const pxeServer = createPXERpcServer(pxeService);
68
+ const rpcServer = createNamespacedJsonRpcServer([{ pxe: pxeServer }]);
69
+
70
+ const app = rpcServer.getApp();
71
+ const httpServer = http.createServer(app.callback());
72
+ httpServer.listen(port);
73
+
74
+ return httpServer;
75
+ }
@@ -0,0 +1,53 @@
1
+ import { AztecNode } from '@aztec/circuit-types';
2
+ import { Grumpkin } from '@aztec/circuits.js/barretenberg';
3
+ import { TestKeyStore } from '@aztec/key-store';
4
+ import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
5
+ import { initStoreForRollup } from '@aztec/kv-store/utils';
6
+ import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer';
7
+ import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
8
+ import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
9
+
10
+ import { join } from 'path';
11
+
12
+ import { PXEServiceConfig } from '../config/index.js';
13
+ import { KVPxeDatabase } from '../database/kv_pxe_database.js';
14
+ import { PXEService } from './pxe_service.js';
15
+
16
+ /**
17
+ * Create and start an PXEService instance with the given AztecNode.
18
+ * If no keyStore or database is provided, it will use TestKeyStore and MemoryDB as default values.
19
+ * Returns a Promise that resolves to the started PXEService instance.
20
+ *
21
+ * @param aztecNode - The AztecNode instance to be used by the server.
22
+ * @param config - The PXE Service Config to use
23
+ * @param options - (Optional) Optional information for creating an PXEService.
24
+ * @returns A Promise that resolves to the started PXEService instance.
25
+ */
26
+ export async function createPXEService(
27
+ aztecNode: AztecNode,
28
+ config: PXEServiceConfig,
29
+ useLogSuffix: string | boolean | undefined = undefined,
30
+ ) {
31
+ const logSuffix =
32
+ typeof useLogSuffix === 'boolean'
33
+ ? useLogSuffix
34
+ ? Math.random().toString(16).slice(2, 8)
35
+ : undefined
36
+ : useLogSuffix;
37
+
38
+ const pxeDbPath = config.dataDirectory ? join(config.dataDirectory, 'pxe_data') : undefined;
39
+ const keyStorePath = config.dataDirectory ? join(config.dataDirectory, 'pxe_key_store') : undefined;
40
+ const l1Contracts = await aztecNode.getL1ContractAddresses();
41
+
42
+ const keyStore = new TestKeyStore(
43
+ new Grumpkin(),
44
+ await initStoreForRollup(AztecLmdbStore.open(keyStorePath), l1Contracts.rollupAddress),
45
+ );
46
+ const db = new KVPxeDatabase(await initStoreForRollup(AztecLmdbStore.open(pxeDbPath), l1Contracts.rollupAddress));
47
+
48
+ const server = new PXEService(keyStore, aztecNode, db, config, logSuffix);
49
+ await server.addContracts([getCanonicalClassRegisterer(), getCanonicalInstanceDeployer(), getCanonicalGasToken()]);
50
+
51
+ await server.start();
52
+ return server;
53
+ }
@@ -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';