@aztec/pxe 0.22.0 → 0.24.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 (53) hide show
  1. package/dest/database/deferred_note_dao.d.ts +4 -0
  2. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  3. package/dest/database/deferred_note_dao.js +6 -3
  4. package/dest/database/note_dao.d.ts +4 -0
  5. package/dest/database/note_dao.d.ts.map +1 -1
  6. package/dest/database/note_dao.js +7 -2
  7. package/dest/database/pxe_database_test_suite.js +2 -2
  8. package/dest/kernel_prover/kernel_prover.js +9 -9
  9. package/dest/kernel_prover/proof_creator.d.ts +10 -10
  10. package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
  11. package/dest/kernel_prover/proof_creator.js +4 -4
  12. package/dest/note_processor/note_processor.d.ts.map +1 -1
  13. package/dest/note_processor/note_processor.js +4 -4
  14. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  15. package/dest/note_processor/produce_note_dao.js +4 -4
  16. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  17. package/dest/pxe_service/create_pxe_service.js +8 -4
  18. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  19. package/dest/pxe_service/pxe_service.js +5 -5
  20. package/package.json +13 -12
  21. package/src/bin/index.ts +42 -0
  22. package/src/config/index.ts +40 -0
  23. package/src/contract_data_oracle/index.ts +185 -0
  24. package/src/contract_data_oracle/private_functions_tree.ts +127 -0
  25. package/src/contract_database/index.ts +1 -0
  26. package/src/contract_database/memory_contract_database.ts +58 -0
  27. package/src/database/contracts/contract_artifact_db.ts +19 -0
  28. package/src/database/contracts/contract_instance_db.ts +18 -0
  29. package/src/database/deferred_note_dao.ts +55 -0
  30. package/src/database/index.ts +1 -0
  31. package/src/database/kv_pxe_database.ts +409 -0
  32. package/src/database/note_dao.ts +97 -0
  33. package/src/database/pxe_database.ts +162 -0
  34. package/src/database/pxe_database_test_suite.ts +258 -0
  35. package/src/index.ts +11 -0
  36. package/src/kernel_oracle/index.ts +61 -0
  37. package/src/kernel_prover/index.ts +2 -0
  38. package/src/kernel_prover/kernel_prover.ts +388 -0
  39. package/src/kernel_prover/proof_creator.ts +157 -0
  40. package/src/kernel_prover/proving_data_oracle.ts +76 -0
  41. package/src/note_processor/index.ts +1 -0
  42. package/src/note_processor/note_processor.ts +282 -0
  43. package/src/note_processor/produce_note_dao.ts +132 -0
  44. package/src/pxe_http/index.ts +1 -0
  45. package/src/pxe_http/pxe_http_server.ts +73 -0
  46. package/src/pxe_service/create_pxe_service.ts +52 -0
  47. package/src/pxe_service/index.ts +3 -0
  48. package/src/pxe_service/pxe_service.ts +756 -0
  49. package/src/pxe_service/test/pxe_test_suite.ts +138 -0
  50. package/src/simulator/index.ts +24 -0
  51. package/src/simulator_oracle/index.ts +210 -0
  52. package/src/synchronizer/index.ts +1 -0
  53. package/src/synchronizer/synchronizer.ts +427 -0
@@ -0,0 +1,409 @@
1
+ import { ContractDao, MerkleTreeId, NoteFilter, NoteStatus, PublicKey } from '@aztec/circuit-types';
2
+ import { AztecAddress, CompleteAddress, Header } from '@aztec/circuits.js';
3
+ import { ContractArtifact } from '@aztec/foundation/abi';
4
+ import { toBufferBE } from '@aztec/foundation/bigint-buffer';
5
+ import { Fr, Point } from '@aztec/foundation/fields';
6
+ import { AztecArray, AztecKVStore, AztecMap, AztecMultiMap, AztecSingleton } from '@aztec/kv-store';
7
+ import { contractArtifactFromBuffer, contractArtifactToBuffer } from '@aztec/types/abi';
8
+ import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts';
9
+
10
+ import { DeferredNoteDao } from './deferred_note_dao.js';
11
+ import { NoteDao } from './note_dao.js';
12
+ import { PxeDatabase } from './pxe_database.js';
13
+
14
+ /**
15
+ * A PXE database backed by LMDB.
16
+ */
17
+ export class KVPxeDatabase implements PxeDatabase {
18
+ #synchronizedBlock: AztecSingleton<Buffer>;
19
+ #addresses: AztecArray<Buffer>;
20
+ #addressIndex: AztecMap<string, number>;
21
+ #authWitnesses: AztecMap<string, Buffer[]>;
22
+ #capsules: AztecArray<Buffer[]>;
23
+ #contracts: AztecMap<string, Buffer>;
24
+ #notes: AztecMap<string, Buffer>;
25
+ #nullifiedNotes: AztecMap<string, Buffer>;
26
+ #nullifierToNoteId: AztecMap<string, string>;
27
+ #notesByContract: AztecMultiMap<string, string>;
28
+ #notesByStorageSlot: AztecMultiMap<string, string>;
29
+ #notesByTxHash: AztecMultiMap<string, string>;
30
+ #notesByOwner: AztecMultiMap<string, string>;
31
+ #nullifiedNotesByContract: AztecMultiMap<string, string>;
32
+ #nullifiedNotesByStorageSlot: AztecMultiMap<string, string>;
33
+ #nullifiedNotesByTxHash: AztecMultiMap<string, string>;
34
+ #nullifiedNotesByOwner: AztecMultiMap<string, string>;
35
+ #deferredNotes: AztecArray<Buffer | null>;
36
+ #deferredNotesByContract: AztecMultiMap<string, number>;
37
+ #syncedBlockPerPublicKey: AztecMap<string, number>;
38
+ #contractArtifacts: AztecMap<string, Buffer>;
39
+ #contractInstances: AztecMap<string, Buffer>;
40
+ #db: AztecKVStore;
41
+
42
+ constructor(private db: AztecKVStore) {
43
+ this.#db = db;
44
+
45
+ this.#addresses = db.openArray('addresses');
46
+ this.#addressIndex = db.openMap('address_index');
47
+
48
+ this.#authWitnesses = db.openMap('auth_witnesses');
49
+ this.#capsules = db.openArray('capsules');
50
+ this.#contracts = db.openMap('contracts');
51
+
52
+ this.#contractArtifacts = db.openMap('contract_artifacts');
53
+ this.#contractInstances = db.openMap('contracts_instances');
54
+
55
+ this.#synchronizedBlock = db.openSingleton('header');
56
+ this.#syncedBlockPerPublicKey = db.openMap('synced_block_per_public_key');
57
+
58
+ this.#notes = db.openMap('notes');
59
+ this.#nullifiedNotes = db.openMap('nullified_notes');
60
+ this.#nullifierToNoteId = db.openMap('nullifier_to_note');
61
+
62
+ this.#notesByContract = db.openMultiMap('notes_by_contract');
63
+ this.#notesByStorageSlot = db.openMultiMap('notes_by_storage_slot');
64
+ this.#notesByTxHash = db.openMultiMap('notes_by_tx_hash');
65
+ this.#notesByOwner = db.openMultiMap('notes_by_owner');
66
+
67
+ this.#nullifiedNotesByContract = db.openMultiMap('nullified_notes_by_contract');
68
+ this.#nullifiedNotesByStorageSlot = db.openMultiMap('nullified_notes_by_storage_slot');
69
+ this.#nullifiedNotesByTxHash = db.openMultiMap('nullified_notes_by_tx_hash');
70
+ this.#nullifiedNotesByOwner = db.openMultiMap('nullified_notes_by_owner');
71
+
72
+ this.#deferredNotes = db.openArray('deferred_notes');
73
+ this.#deferredNotesByContract = db.openMultiMap('deferred_notes_by_contract');
74
+ }
75
+
76
+ public async addContractArtifact(id: Fr, contract: ContractArtifact): Promise<void> {
77
+ await this.#contractArtifacts.set(id.toString(), contractArtifactToBuffer(contract));
78
+ }
79
+
80
+ getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
81
+ const contract = this.#contractArtifacts.get(id.toString());
82
+ // TODO(@spalladino): AztecMap lies and returns Uint8Arrays instead of Buffers, hence the extra Buffer.from.
83
+ return Promise.resolve(contract && contractArtifactFromBuffer(Buffer.from(contract)));
84
+ }
85
+
86
+ async addContractInstance(contract: ContractInstanceWithAddress): Promise<void> {
87
+ await this.#contractInstances.set(
88
+ contract.address.toString(),
89
+ new SerializableContractInstance(contract).toBuffer(),
90
+ );
91
+ }
92
+
93
+ getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
94
+ const contract = this.#contractInstances.get(address.toString());
95
+ return Promise.resolve(contract && SerializableContractInstance.fromBuffer(contract).withAddress(address));
96
+ }
97
+
98
+ async addAuthWitness(messageHash: Fr, witness: Fr[]): Promise<void> {
99
+ await this.#authWitnesses.set(
100
+ messageHash.toString(),
101
+ witness.map(w => w.toBuffer()),
102
+ );
103
+ }
104
+
105
+ getAuthWitness(messageHash: Fr): Promise<Fr[] | undefined> {
106
+ const witness = this.#authWitnesses.get(messageHash.toString());
107
+ return Promise.resolve(witness?.map(w => Fr.fromBuffer(w)));
108
+ }
109
+
110
+ async addCapsule(capsule: Fr[]): Promise<void> {
111
+ await this.#capsules.push(capsule.map(c => c.toBuffer()));
112
+ }
113
+
114
+ async popCapsule(): Promise<Fr[] | undefined> {
115
+ const val = await this.#capsules.pop();
116
+ return val?.map(b => Fr.fromBuffer(b));
117
+ }
118
+
119
+ async addNote(note: NoteDao): Promise<void> {
120
+ await this.addNotes([note]);
121
+ }
122
+
123
+ addNotes(notes: NoteDao[]): Promise<void> {
124
+ return this.db.transaction(() => {
125
+ for (const dao of notes) {
126
+ // store notes by their index in the notes hash tree
127
+ // this provides the uniqueness we need to store individual notes
128
+ // and should also return notes in the order that they were created.
129
+ // Had we stored them by their nullifier, they would be returned in random order
130
+ const noteIndex = toBufferBE(dao.index, 32).toString('hex');
131
+ void this.#notes.set(noteIndex, dao.toBuffer());
132
+ void this.#nullifierToNoteId.set(dao.siloedNullifier.toString(), noteIndex);
133
+ void this.#notesByContract.set(dao.contractAddress.toString(), noteIndex);
134
+ void this.#notesByStorageSlot.set(dao.storageSlot.toString(), noteIndex);
135
+ void this.#notesByTxHash.set(dao.txHash.toString(), noteIndex);
136
+ void this.#notesByOwner.set(dao.publicKey.toString(), noteIndex);
137
+ }
138
+ });
139
+ }
140
+
141
+ async addDeferredNotes(deferredNotes: DeferredNoteDao[]): Promise<void> {
142
+ const newLength = await this.#deferredNotes.push(...deferredNotes.map(note => note.toBuffer()));
143
+ for (const [index, note] of deferredNotes.entries()) {
144
+ const noteId = newLength - deferredNotes.length + index;
145
+ await this.#deferredNotesByContract.set(note.contractAddress.toString(), noteId);
146
+ }
147
+ }
148
+
149
+ getDeferredNotesByContract(contractAddress: AztecAddress): Promise<DeferredNoteDao[]> {
150
+ const noteIds = this.#deferredNotesByContract.getValues(contractAddress.toString());
151
+ const notes: DeferredNoteDao[] = [];
152
+ for (const noteId of noteIds) {
153
+ const serializedNote = this.#deferredNotes.at(noteId);
154
+ if (!serializedNote) {
155
+ continue;
156
+ }
157
+
158
+ const note = DeferredNoteDao.fromBuffer(serializedNote);
159
+ notes.push(note);
160
+ }
161
+
162
+ return Promise.resolve(notes);
163
+ }
164
+
165
+ /**
166
+ * Removes all deferred notes for a given contract address.
167
+ * @param contractAddress - the contract address to remove deferred notes for
168
+ * @returns an array of the removed deferred notes
169
+ */
170
+ removeDeferredNotesByContract(contractAddress: AztecAddress): Promise<DeferredNoteDao[]> {
171
+ return this.#db.transaction(() => {
172
+ const deferredNotes: DeferredNoteDao[] = [];
173
+ const indices = this.#deferredNotesByContract.getValues(contractAddress.toString());
174
+
175
+ for (const index of indices) {
176
+ const deferredNoteBuffer = this.#deferredNotes.at(index);
177
+ if (!deferredNoteBuffer) {
178
+ continue;
179
+ } else {
180
+ deferredNotes.push(DeferredNoteDao.fromBuffer(deferredNoteBuffer));
181
+ }
182
+
183
+ void this.#deferredNotesByContract.deleteValue(contractAddress.toString(), index);
184
+ void this.#deferredNotes.setAt(index, null);
185
+ }
186
+
187
+ return deferredNotes;
188
+ });
189
+ }
190
+
191
+ #getNotes(filter: NoteFilter): NoteDao[] {
192
+ const publicKey: PublicKey | undefined = filter.owner
193
+ ? this.#getCompleteAddress(filter.owner)?.publicKey
194
+ : undefined;
195
+
196
+ filter.status = filter.status ?? NoteStatus.ACTIVE;
197
+
198
+ const candidateNoteSources = [];
199
+
200
+ candidateNoteSources.push({
201
+ ids: publicKey
202
+ ? this.#notesByOwner.getValues(publicKey.toString())
203
+ : filter.txHash
204
+ ? this.#notesByTxHash.getValues(filter.txHash.toString())
205
+ : filter.contractAddress
206
+ ? this.#notesByContract.getValues(filter.contractAddress.toString())
207
+ : filter.storageSlot
208
+ ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString())
209
+ : this.#notes.keys(),
210
+ notes: this.#notes,
211
+ });
212
+
213
+ if (filter.status == NoteStatus.ACTIVE_OR_NULLIFIED) {
214
+ candidateNoteSources.push({
215
+ ids: publicKey
216
+ ? this.#nullifiedNotesByOwner.getValues(publicKey.toString())
217
+ : filter.txHash
218
+ ? this.#nullifiedNotesByTxHash.getValues(filter.txHash.toString())
219
+ : filter.contractAddress
220
+ ? this.#nullifiedNotesByContract.getValues(filter.contractAddress.toString())
221
+ : filter.storageSlot
222
+ ? this.#nullifiedNotesByStorageSlot.getValues(filter.storageSlot.toString())
223
+ : this.#nullifiedNotes.keys(),
224
+ notes: this.#nullifiedNotes,
225
+ });
226
+ }
227
+
228
+ const result: NoteDao[] = [];
229
+ for (const { ids, notes } of candidateNoteSources) {
230
+ for (const id of ids) {
231
+ const serializedNote = notes.get(id);
232
+ if (!serializedNote) {
233
+ continue;
234
+ }
235
+
236
+ const note = NoteDao.fromBuffer(serializedNote);
237
+ if (filter.contractAddress && !note.contractAddress.equals(filter.contractAddress)) {
238
+ continue;
239
+ }
240
+
241
+ if (filter.txHash && !note.txHash.equals(filter.txHash)) {
242
+ continue;
243
+ }
244
+
245
+ if (filter.storageSlot && !note.storageSlot.equals(filter.storageSlot!)) {
246
+ continue;
247
+ }
248
+
249
+ if (publicKey && !note.publicKey.equals(publicKey)) {
250
+ continue;
251
+ }
252
+
253
+ result.push(note);
254
+ }
255
+ }
256
+
257
+ return result;
258
+ }
259
+
260
+ getNotes(filter: NoteFilter): Promise<NoteDao[]> {
261
+ return Promise.resolve(this.#getNotes(filter));
262
+ }
263
+
264
+ removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<NoteDao[]> {
265
+ if (nullifiers.length === 0) {
266
+ return Promise.resolve([]);
267
+ }
268
+
269
+ return this.#db.transaction(() => {
270
+ const nullifiedNotes: NoteDao[] = [];
271
+
272
+ for (const nullifier of nullifiers) {
273
+ const noteIndex = this.#nullifierToNoteId.get(nullifier.toString());
274
+ if (!noteIndex) {
275
+ continue;
276
+ }
277
+
278
+ const noteBuffer = noteIndex ? this.#notes.get(noteIndex) : undefined;
279
+
280
+ if (!noteBuffer) {
281
+ // note doesn't exist. Maybe it got nullified already
282
+ continue;
283
+ }
284
+
285
+ const note = NoteDao.fromBuffer(noteBuffer);
286
+ if (!note.publicKey.equals(account)) {
287
+ // tried to nullify someone else's note
288
+ continue;
289
+ }
290
+
291
+ nullifiedNotes.push(note);
292
+
293
+ void this.#notes.delete(noteIndex);
294
+ void this.#notesByOwner.deleteValue(account.toString(), noteIndex);
295
+ void this.#notesByTxHash.deleteValue(note.txHash.toString(), noteIndex);
296
+ void this.#notesByContract.deleteValue(note.contractAddress.toString(), noteIndex);
297
+ void this.#notesByStorageSlot.deleteValue(note.storageSlot.toString(), noteIndex);
298
+
299
+ void this.#nullifiedNotes.set(noteIndex, note.toBuffer());
300
+ void this.#nullifiedNotesByContract.set(note.contractAddress.toString(), noteIndex);
301
+ void this.#nullifiedNotesByStorageSlot.set(note.storageSlot.toString(), noteIndex);
302
+ void this.#nullifiedNotesByTxHash.set(note.txHash.toString(), noteIndex);
303
+ void this.#nullifiedNotesByOwner.set(note.publicKey.toString(), noteIndex);
304
+
305
+ void this.#nullifierToNoteId.delete(nullifier.toString());
306
+ }
307
+
308
+ return nullifiedNotes;
309
+ });
310
+ }
311
+
312
+ async setHeader(header: Header): Promise<void> {
313
+ await this.#synchronizedBlock.set(header.toBuffer());
314
+ }
315
+
316
+ getBlockNumber(): number | undefined {
317
+ const headerBuffer = this.#synchronizedBlock.get();
318
+ if (!headerBuffer) {
319
+ return undefined;
320
+ }
321
+
322
+ return Number(Header.fromBuffer(headerBuffer).globalVariables.blockNumber.toBigInt());
323
+ }
324
+
325
+ getHeader(): Header {
326
+ const headerBuffer = this.#synchronizedBlock.get();
327
+ if (!headerBuffer) {
328
+ throw new Error(`Header not set`);
329
+ }
330
+
331
+ return Header.fromBuffer(headerBuffer);
332
+ }
333
+
334
+ addCompleteAddress(completeAddress: CompleteAddress): Promise<boolean> {
335
+ return this.#db.transaction(() => {
336
+ const addressString = completeAddress.address.toString();
337
+ const buffer = completeAddress.toBuffer();
338
+ const existing = this.#addressIndex.get(addressString);
339
+ if (typeof existing === 'undefined') {
340
+ const index = this.#addresses.length;
341
+ void this.#addresses.push(buffer);
342
+ void this.#addressIndex.set(addressString, index);
343
+
344
+ return true;
345
+ } else {
346
+ const existingBuffer = this.#addresses.at(existing);
347
+
348
+ if (existingBuffer?.equals(buffer)) {
349
+ return false;
350
+ }
351
+
352
+ throw new Error(
353
+ `Complete address with aztec address ${addressString} but different public key or partial key already exists in memory database`,
354
+ );
355
+ }
356
+ });
357
+ }
358
+
359
+ #getCompleteAddress(address: AztecAddress): CompleteAddress | undefined {
360
+ const index = this.#addressIndex.get(address.toString());
361
+ if (typeof index === 'undefined') {
362
+ return undefined;
363
+ }
364
+
365
+ const value = this.#addresses.at(index);
366
+ return value ? CompleteAddress.fromBuffer(value) : undefined;
367
+ }
368
+
369
+ getCompleteAddress(address: AztecAddress): Promise<CompleteAddress | undefined> {
370
+ return Promise.resolve(this.#getCompleteAddress(address));
371
+ }
372
+
373
+ getCompleteAddresses(): Promise<CompleteAddress[]> {
374
+ return Promise.resolve(Array.from(this.#addresses).map(v => CompleteAddress.fromBuffer(v)));
375
+ }
376
+
377
+ getSynchedBlockNumberForPublicKey(publicKey: Point): number | undefined {
378
+ return this.#syncedBlockPerPublicKey.get(publicKey.toString());
379
+ }
380
+
381
+ setSynchedBlockNumberForPublicKey(publicKey: Point, blockNumber: number): Promise<boolean> {
382
+ return this.#syncedBlockPerPublicKey.set(publicKey.toString(), blockNumber);
383
+ }
384
+
385
+ estimateSize(): number {
386
+ const notesSize = Array.from(this.#getNotes({})).reduce((sum, note) => sum + note.getSize(), 0);
387
+ const authWitsSize = Array.from(this.#authWitnesses.values()).reduce(
388
+ (sum, value) => sum + value.length * Fr.SIZE_IN_BYTES,
389
+ 0,
390
+ );
391
+ const addressesSize = this.#addresses.length * CompleteAddress.SIZE_IN_BYTES;
392
+ const treeRootsSize = Object.keys(MerkleTreeId).length * Fr.SIZE_IN_BYTES;
393
+
394
+ return notesSize + treeRootsSize + authWitsSize + addressesSize;
395
+ }
396
+
397
+ async addContract(contract: ContractDao): Promise<void> {
398
+ await this.#contracts.set(contract.instance.address.toString(), contract.toBuffer());
399
+ }
400
+
401
+ getContract(address: AztecAddress): Promise<ContractDao | undefined> {
402
+ const contract = this.#contracts.get(address.toString());
403
+ return Promise.resolve(contract ? ContractDao.fromBuffer(contract) : undefined);
404
+ }
405
+
406
+ getContracts(): Promise<ContractDao[]> {
407
+ return Promise.resolve(Array.from(this.#contracts.values()).map(c => ContractDao.fromBuffer(c)));
408
+ }
409
+ }
@@ -0,0 +1,97 @@
1
+ import { Note, TxHash } from '@aztec/circuit-types';
2
+ import { AztecAddress, Fr, Point, PublicKey } from '@aztec/circuits.js';
3
+ import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer';
4
+ import { BufferReader } from '@aztec/foundation/serialize';
5
+ import { NoteData } from '@aztec/simulator';
6
+
7
+ /**
8
+ * A note with contextual data.
9
+ */
10
+ export class NoteDao implements NoteData {
11
+ constructor(
12
+ /** The note as emitted from the Noir contract. */
13
+ public note: Note,
14
+ /** The contract address this note is created in. */
15
+ public contractAddress: AztecAddress,
16
+ /** The specific storage location of the note on the contract. */
17
+ public storageSlot: Fr,
18
+ /** The note type identifier for the contract. */
19
+ public noteTypeId: Fr,
20
+ /** The hash of the tx the note was created in. */
21
+ public txHash: TxHash,
22
+ /** The nonce of the note. */
23
+ public nonce: Fr,
24
+ /**
25
+ * Inner note hash of the note. This is customizable by the app circuit.
26
+ * We can use this value to compute siloedNoteHash and uniqueSiloedNoteHash.
27
+ */
28
+ public innerNoteHash: Fr,
29
+ /** The nullifier of the note (siloed by contract address). */
30
+ public siloedNullifier: Fr,
31
+ /** The location of the relevant note in the note hash tree. */
32
+ public index: bigint,
33
+ /** The public key with which the note was encrypted. */
34
+ public publicKey: PublicKey,
35
+ ) {}
36
+
37
+ toBuffer(): Buffer {
38
+ return Buffer.concat([
39
+ this.note.toBuffer(),
40
+ this.contractAddress.toBuffer(),
41
+ this.storageSlot.toBuffer(),
42
+ this.noteTypeId.toBuffer(),
43
+ this.txHash.buffer,
44
+ this.nonce.toBuffer(),
45
+ this.innerNoteHash.toBuffer(),
46
+ this.siloedNullifier.toBuffer(),
47
+ toBufferBE(this.index, 32),
48
+ this.publicKey.toBuffer(),
49
+ ]);
50
+ }
51
+ static fromBuffer(buffer: Buffer | BufferReader) {
52
+ const reader = BufferReader.asReader(buffer);
53
+
54
+ const note = Note.fromBuffer(reader);
55
+ const contractAddress = AztecAddress.fromBuffer(reader);
56
+ const storageSlot = Fr.fromBuffer(reader);
57
+ const noteTypeId = Fr.fromBuffer(reader);
58
+ const txHash = new TxHash(reader.readBytes(TxHash.SIZE));
59
+ const nonce = Fr.fromBuffer(reader);
60
+ const innerNoteHash = Fr.fromBuffer(reader);
61
+ const siloedNullifier = Fr.fromBuffer(reader);
62
+ const index = toBigIntBE(reader.readBytes(32));
63
+ const publicKey = Point.fromBuffer(reader);
64
+
65
+ return new NoteDao(
66
+ note,
67
+ contractAddress,
68
+ storageSlot,
69
+ noteTypeId,
70
+ txHash,
71
+ nonce,
72
+ innerNoteHash,
73
+ siloedNullifier,
74
+ index,
75
+ publicKey,
76
+ );
77
+ }
78
+
79
+ toString() {
80
+ return '0x' + this.toBuffer().toString('hex');
81
+ }
82
+
83
+ static fromString(str: string) {
84
+ const hex = str.replace(/^0x/, '');
85
+ return NoteDao.fromBuffer(Buffer.from(hex, 'hex'));
86
+ }
87
+
88
+ /**
89
+ * Returns the size in bytes of the Note Dao.
90
+ * @returns - Its size in bytes.
91
+ */
92
+ public getSize() {
93
+ const indexSize = Math.ceil(Math.log2(Number(this.index)));
94
+ const noteSize = 4 + this.note.items.length * Fr.SIZE_IN_BYTES;
95
+ return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 4 + TxHash.SIZE + Point.SIZE_IN_BYTES + indexSize;
96
+ }
97
+ }
@@ -0,0 +1,162 @@
1
+ import { ContractDatabase, NoteFilter } from '@aztec/circuit-types';
2
+ import { CompleteAddress, Header, PublicKey } from '@aztec/circuits.js';
3
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
4
+ import { Fr } from '@aztec/foundation/fields';
5
+
6
+ import { ContractArtifactDatabase } from './contracts/contract_artifact_db.js';
7
+ import { ContractInstanceDatabase } from './contracts/contract_instance_db.js';
8
+ import { DeferredNoteDao } from './deferred_note_dao.js';
9
+ import { NoteDao } from './note_dao.js';
10
+
11
+ /**
12
+ * A database interface that provides methods for retrieving, adding, and removing transactional data related to Aztec
13
+ * addresses, storage slots, and nullifiers.
14
+ */
15
+ export interface PxeDatabase extends ContractDatabase, ContractArtifactDatabase, ContractInstanceDatabase {
16
+ /**
17
+ * Add a auth witness to the database.
18
+ * @param messageHash - The message hash.
19
+ * @param witness - An array of field elements representing the auth witness.
20
+ */
21
+ addAuthWitness(messageHash: Fr, witness: Fr[]): Promise<void>;
22
+
23
+ /**
24
+ * Fetching the auth witness for a given message hash.
25
+ * @param messageHash - The message hash.
26
+ * @returns A Promise that resolves to an array of field elements representing the auth witness.
27
+ */
28
+ getAuthWitness(messageHash: Fr): Promise<Fr[] | undefined>;
29
+
30
+ /**
31
+ * Adding a capsule to the capsule dispenser.
32
+ * @remarks A capsule is a "blob" of data that is passed to the contract through an oracle.
33
+ * @param capsule - An array of field elements representing the capsule.
34
+ */
35
+ addCapsule(capsule: Fr[]): Promise<void>;
36
+
37
+ /**
38
+ * Get the next capsule from the capsule dispenser.
39
+ * @remarks A capsule is a "blob" of data that is passed to the contract through an oracle.
40
+ * @returns A promise that resolves to an array of field elements representing the capsule.
41
+ */
42
+ popCapsule(): Promise<Fr[] | undefined>;
43
+
44
+ /**
45
+ * Gets notes based on the provided filter.
46
+ * @param filter - The filter to apply to the notes.
47
+ * @returns The requested notes.
48
+ */
49
+ getNotes(filter: NoteFilter): Promise<NoteDao[]>;
50
+
51
+ /**
52
+ * Adds a note to DB.
53
+ * @param note - The note to add.
54
+ */
55
+ addNote(note: NoteDao): Promise<void>;
56
+
57
+ /**
58
+ * Adds an array of notes to DB.
59
+ * This function is used to insert multiple notes to the database at once,
60
+ * which can improve performance when dealing with large numbers of transactions.
61
+ *
62
+ * @param notes - An array of notes.
63
+ */
64
+ addNotes(notes: NoteDao[]): Promise<void>;
65
+
66
+ /**
67
+ * Add notes to the database that are intended for us, but we don't yet have the contract.
68
+ * @param deferredNotes - An array of deferred notes.
69
+ */
70
+ addDeferredNotes(deferredNotes: DeferredNoteDao[]): Promise<void>;
71
+
72
+ /**
73
+ * Get deferred notes for a given contract address.
74
+ * @param contractAddress - The contract address to get the deferred notes for.
75
+ */
76
+ getDeferredNotesByContract(contractAddress: AztecAddress): Promise<DeferredNoteDao[]>;
77
+
78
+ /**
79
+ * Remove deferred notes for a given contract address.
80
+ * @param contractAddress - The contract address to remove the deferred notes for.
81
+ * @returns an array of the removed deferred notes
82
+ */
83
+ removeDeferredNotesByContract(contractAddress: AztecAddress): Promise<DeferredNoteDao[]>;
84
+
85
+ /**
86
+ * Remove nullified notes associated with the given account and nullifiers.
87
+ *
88
+ * @param nullifiers - An array of Fr instances representing nullifiers to be matched.
89
+ * @param account - A PublicKey instance representing the account for which the records are being removed.
90
+ * @returns Removed notes.
91
+ */
92
+ removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<NoteDao[]>;
93
+
94
+ /**
95
+ * Gets the most recently processed block number.
96
+ * @returns The most recently processed block number or undefined if never synched.
97
+ */
98
+ getBlockNumber(): number | undefined;
99
+
100
+ /**
101
+ * Retrieve the stored Block Header from the database.
102
+ * The function returns a Promise that resolves to the Block Header.
103
+ * This data is required to reproduce block attestations.
104
+ * Throws an error if the block header is not available within the database.
105
+ *
106
+ * note: this data is a combination of the tree roots and the global variables hash.
107
+ *
108
+ * @returns The Block Header.
109
+ * @throws If no block have been processed yet.
110
+ */
111
+ getHeader(): Header;
112
+
113
+ /**
114
+ * Set the latest Block Header.
115
+ * Note that this will overwrite any existing hash or roots in the database.
116
+ *
117
+ * @param header - An object containing the most recent block header.
118
+ * @returns A Promise that resolves when the hash has been successfully updated in the database.
119
+ */
120
+ setHeader(header: Header): Promise<void>;
121
+
122
+ /**
123
+ * Adds complete address to the database.
124
+ * @param address - The complete address to add.
125
+ * @returns A promise resolving to true if the address was added, false if it already exists.
126
+ * @throws If we try to add a CompleteAddress with the same AztecAddress but different public key or partial
127
+ * address.
128
+ */
129
+ addCompleteAddress(address: CompleteAddress): Promise<boolean>;
130
+
131
+ /**
132
+ * Retrieves the complete address corresponding to the provided aztec address.
133
+ * @param address - The aztec address of the complete address contract.
134
+ * @returns A promise that resolves to a CompleteAddress instance if the address is found, or undefined if not found.
135
+ */
136
+ getCompleteAddress(address: AztecAddress): Promise<CompleteAddress | undefined>;
137
+
138
+ /**
139
+ * Retrieves the list of complete address added to this database
140
+ * @returns A promise that resolves to an array of AztecAddress instances.
141
+ */
142
+ getCompleteAddresses(): Promise<CompleteAddress[]>;
143
+
144
+ /**
145
+ * Updates up to which block number we have processed notes for a given public key.
146
+ * @param publicKey - The public key to set the synched block number for.
147
+ * @param blockNumber - The block number to set.
148
+ */
149
+ setSynchedBlockNumberForPublicKey(publicKey: PublicKey, blockNumber: number): Promise<boolean>;
150
+
151
+ /**
152
+ * Get the synched block number for a given public key.
153
+ * @param publicKey - The public key to get the synched block number for.
154
+ */
155
+ getSynchedBlockNumberForPublicKey(publicKey: PublicKey): number | undefined;
156
+
157
+ /**
158
+ * Returns the estimated size in bytes of this db.
159
+ * @returns The estimated size in bytes of this db.
160
+ */
161
+ estimateSize(): number;
162
+ }