@aztec/pxe 0.42.0 → 0.43.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 (47) hide show
  1. package/dest/database/deferred_note_dao.d.ts +2 -2
  2. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  3. package/dest/database/deferred_note_dao.js +2 -2
  4. package/dest/database/incoming_note_dao.d.ts +73 -0
  5. package/dest/database/incoming_note_dao.d.ts.map +1 -0
  6. package/dest/database/incoming_note_dao.js +92 -0
  7. package/dest/database/kv_pxe_database.d.ts +10 -7
  8. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  9. package/dest/database/kv_pxe_database.js +149 -78
  10. package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +7 -12
  11. package/dest/database/outgoing_note_dao.d.ts.map +1 -0
  12. package/dest/database/outgoing_note_dao.js +83 -0
  13. package/dest/database/pxe_database.d.ts +21 -9
  14. package/dest/database/pxe_database.d.ts.map +1 -1
  15. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  16. package/dest/database/pxe_database_test_suite.js +71 -24
  17. package/dest/kernel_oracle/index.d.ts +1 -1
  18. package/dest/note_processor/note_processor.d.ts +23 -20
  19. package/dest/note_processor/note_processor.d.ts.map +1 -1
  20. package/dest/note_processor/note_processor.js +123 -76
  21. package/dest/note_processor/produce_note_dao.d.ts +13 -4
  22. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  23. package/dest/note_processor/produce_note_dao.js +88 -31
  24. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  25. package/dest/pxe_service/create_pxe_service.js +3 -1
  26. package/dest/pxe_service/pxe_service.d.ts +9 -4
  27. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  28. package/dest/pxe_service/pxe_service.js +106 -28
  29. package/dest/simulator_oracle/index.js +2 -2
  30. package/dest/synchronizer/synchronizer.d.ts +2 -2
  31. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  32. package/dest/synchronizer/synchronizer.js +37 -36
  33. package/package.json +14 -14
  34. package/src/database/deferred_note_dao.ts +1 -1
  35. package/src/database/{note_dao.ts → incoming_note_dao.ts} +10 -7
  36. package/src/database/kv_pxe_database.ts +127 -29
  37. package/src/database/outgoing_note_dao.ts +90 -0
  38. package/src/database/pxe_database.ts +23 -9
  39. package/src/database/pxe_database_test_suite.ts +93 -29
  40. package/src/note_processor/note_processor.ts +191 -121
  41. package/src/note_processor/produce_note_dao.ts +164 -50
  42. package/src/pxe_service/create_pxe_service.ts +2 -0
  43. package/src/pxe_service/pxe_service.ts +170 -42
  44. package/src/simulator_oracle/index.ts +1 -1
  45. package/src/synchronizer/synchronizer.ts +48 -52
  46. package/dest/database/note_dao.d.ts.map +0 -1
  47. package/dest/database/note_dao.js +0 -89
@@ -0,0 +1,90 @@
1
+ import { Note, TxHash } from '@aztec/circuit-types';
2
+ import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
3
+ import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
4
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
5
+
6
+ /**
7
+ * A note with contextual data which was decrypted as outgoing.
8
+ */
9
+ export class OutgoingNoteDao {
10
+ constructor(
11
+ /** The note as emitted from the Noir contract. */
12
+ public note: Note,
13
+ /** The contract address this note is created in. */
14
+ public contractAddress: AztecAddress,
15
+ /** The specific storage location of the note on the contract. */
16
+ public storageSlot: Fr,
17
+ /** The note type identifier for the contract. */
18
+ public noteTypeId: Fr,
19
+ /** The hash of the tx the note was created in. */
20
+ public txHash: TxHash,
21
+ /** The nonce of the note. */
22
+ public nonce: Fr,
23
+ /**
24
+ * Inner note hash of the note. This is customizable by the app circuit.
25
+ * We can use this value to compute siloedNoteHash and uniqueSiloedNoteHash.
26
+ */
27
+ public innerNoteHash: Fr,
28
+ /** The location of the relevant note in the note hash tree. */
29
+ public index: bigint,
30
+ /** The public key with which the note was encrypted. */
31
+ public ovpkM: PublicKey,
32
+ ) {}
33
+
34
+ toBuffer(): Buffer {
35
+ return serializeToBuffer([
36
+ this.note,
37
+ this.contractAddress,
38
+ this.storageSlot,
39
+ this.noteTypeId,
40
+ this.txHash.buffer,
41
+ this.nonce,
42
+ this.innerNoteHash,
43
+ this.index,
44
+ this.ovpkM,
45
+ ]);
46
+ }
47
+ static fromBuffer(buffer: Buffer | BufferReader) {
48
+ const reader = BufferReader.asReader(buffer);
49
+
50
+ const note = Note.fromBuffer(reader);
51
+ const contractAddress = AztecAddress.fromBuffer(reader);
52
+ const storageSlot = Fr.fromBuffer(reader);
53
+ const noteTypeId = Fr.fromBuffer(reader);
54
+ const txHash = new TxHash(reader.readBytes(TxHash.SIZE));
55
+ const nonce = Fr.fromBuffer(reader);
56
+ const innerNoteHash = Fr.fromBuffer(reader);
57
+ const index = toBigIntBE(reader.readBytes(32));
58
+ const publicKey = Point.fromBuffer(reader);
59
+
60
+ return new OutgoingNoteDao(
61
+ note,
62
+ contractAddress,
63
+ storageSlot,
64
+ noteTypeId,
65
+ txHash,
66
+ nonce,
67
+ innerNoteHash,
68
+ index,
69
+ publicKey,
70
+ );
71
+ }
72
+
73
+ toString() {
74
+ return '0x' + this.toBuffer().toString('hex');
75
+ }
76
+
77
+ static fromString(str: string) {
78
+ const hex = str.replace(/^0x/, '');
79
+ return OutgoingNoteDao.fromBuffer(Buffer.from(hex, 'hex'));
80
+ }
81
+
82
+ /**
83
+ * Returns the size in bytes of the Note Dao.
84
+ * @returns - Its size in bytes.
85
+ */
86
+ public getSize() {
87
+ const noteSize = 4 + this.note.items.length * Fr.SIZE_IN_BYTES;
88
+ return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 2 + TxHash.SIZE + Point.SIZE_IN_BYTES;
89
+ }
90
+ }
@@ -1,4 +1,4 @@
1
- import { type NoteFilter } from '@aztec/circuit-types';
1
+ import { type IncomingNotesFilter, type OutgoingNotesFilter } from '@aztec/circuit-types';
2
2
  import { type CompleteAddress, type Header, type PublicKey } from '@aztec/circuits.js';
3
3
  import { type ContractArtifact } from '@aztec/foundation/abi';
4
4
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
@@ -8,7 +8,8 @@ import { type ContractInstanceWithAddress } from '@aztec/types/contracts';
8
8
  import { type ContractArtifactDatabase } from './contracts/contract_artifact_db.js';
9
9
  import { type ContractInstanceDatabase } from './contracts/contract_instance_db.js';
10
10
  import { type DeferredNoteDao } from './deferred_note_dao.js';
11
- import { type NoteDao } from './note_dao.js';
11
+ import { type IncomingNoteDao } from './incoming_note_dao.js';
12
+ import { type OutgoingNoteDao } from './outgoing_note_dao.js';
12
13
 
13
14
  /**
14
15
  * A database interface that provides methods for retrieving, adding, and removing transactional data related to Aztec
@@ -46,26 +47,39 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
46
47
  popCapsule(): Promise<Fr[] | undefined>;
47
48
 
48
49
  /**
49
- * Gets notes based on the provided filter.
50
+ * Gets incoming notes based on the provided filter.
50
51
  * @param filter - The filter to apply to the notes.
51
52
  * @returns The requested notes.
52
53
  */
53
- getNotes(filter: NoteFilter): Promise<NoteDao[]>;
54
+ getIncomingNotes(filter: IncomingNotesFilter): Promise<IncomingNoteDao[]>;
55
+
56
+ /**
57
+ * Gets outgoing notes.
58
+ * @returns The outgoing notes.
59
+ */
60
+ getOutgoingNotes(filter: OutgoingNotesFilter): Promise<OutgoingNoteDao[]>;
54
61
 
55
62
  /**
56
63
  * Adds a note to DB.
57
64
  * @param note - The note to add.
58
65
  */
59
- addNote(note: NoteDao): Promise<void>;
66
+ addNote(note: IncomingNoteDao): Promise<void>;
67
+
68
+ /**
69
+ * Adds a nullified note to DB.
70
+ * @param note - The note to add.
71
+ */
72
+ addNullifiedNote(note: IncomingNoteDao): Promise<void>;
60
73
 
61
74
  /**
62
75
  * Adds an array of notes to DB.
63
76
  * This function is used to insert multiple notes to the database at once,
64
77
  * which can improve performance when dealing with large numbers of transactions.
65
78
  *
66
- * @param notes - An array of notes.
79
+ * @param incomingNotes - An array of notes which were decrypted as incoming.
80
+ * @param outgoingNotes - An array of notes which were decrypted as outgoing.
67
81
  */
68
- addNotes(notes: NoteDao[]): Promise<void>;
82
+ addNotes(incomingNotes: IncomingNoteDao[], outgoingNotes: OutgoingNoteDao[]): Promise<void>;
69
83
 
70
84
  /**
71
85
  * Add notes to the database that are intended for us, but we don't yet have the contract.
@@ -93,7 +107,7 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
93
107
  * @param account - A PublicKey instance representing the account for which the records are being removed.
94
108
  * @returns Removed notes.
95
109
  */
96
- removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<NoteDao[]>;
110
+ removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<IncomingNoteDao[]>;
97
111
 
98
112
  /**
99
113
  * Gets the most recently processed block number.
@@ -162,5 +176,5 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
162
176
  * Returns the estimated size in bytes of this db.
163
177
  * @returns The estimated size in bytes of this db.
164
178
  */
165
- estimateSize(): number;
179
+ estimateSize(): Promise<number>;
166
180
  }
@@ -1,4 +1,4 @@
1
- import { type NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types';
1
+ import { type IncomingNotesFilter, NoteStatus, type OutgoingNotesFilter, randomTxHash } from '@aztec/circuit-types';
2
2
  import { AztecAddress, CompleteAddress, INITIAL_L2_BLOCK_NUM, PublicKeys } from '@aztec/circuits.js';
3
3
  import { makeHeader } from '@aztec/circuits.js/testing';
4
4
  import { randomInt } from '@aztec/foundation/crypto';
@@ -6,8 +6,10 @@ import { Fr, Point } from '@aztec/foundation/fields';
6
6
  import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking';
7
7
  import { SerializableContractInstance } from '@aztec/types/contracts';
8
8
 
9
- import { type NoteDao } from './note_dao.js';
10
- import { randomNoteDao } from './note_dao.test.js';
9
+ import { type IncomingNoteDao } from './incoming_note_dao.js';
10
+ import { randomIncomingNoteDao } from './incoming_note_dao.test.js';
11
+ import { type OutgoingNoteDao } from './outgoing_note_dao.js';
12
+ import { randomOutgoingNoteDao } from './outgoing_note_dao.test.js';
11
13
  import { type PxeDatabase } from './pxe_database.js';
12
14
 
13
15
  /**
@@ -68,13 +70,13 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
68
70
  });
69
71
  });
70
72
 
71
- describe('notes', () => {
73
+ describe('incoming notes', () => {
72
74
  let owners: CompleteAddress[];
73
75
  let contractAddresses: AztecAddress[];
74
76
  let storageSlots: Fr[];
75
- let notes: NoteDao[];
77
+ let notes: IncomingNoteDao[];
76
78
 
77
- const filteringTests: [() => NoteFilter, () => NoteDao[]][] = [
79
+ const filteringTests: [() => IncomingNotesFilter, () => IncomingNoteDao[]][] = [
78
80
  [() => ({}), () => notes],
79
81
 
80
82
  [
@@ -94,7 +96,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
94
96
 
95
97
  [
96
98
  () => ({ owner: owners[0].address }),
97
- () => notes.filter(note => note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey)),
99
+ () => notes.filter(note => note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey)),
98
100
  ],
99
101
 
100
102
  [
@@ -107,46 +109,44 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
107
109
  [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []],
108
110
  ];
109
111
 
110
- beforeEach(() => {
112
+ beforeEach(async () => {
111
113
  owners = Array.from({ length: 2 }).map(() => CompleteAddress.random());
112
114
  contractAddresses = Array.from({ length: 2 }).map(() => AztecAddress.random());
113
115
  storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
114
116
 
115
117
  notes = Array.from({ length: 10 }).map((_, i) =>
116
- randomNoteDao({
118
+ randomIncomingNoteDao({
117
119
  contractAddress: contractAddresses[i % contractAddresses.length],
118
120
  storageSlot: storageSlots[i % storageSlots.length],
119
- publicKey: owners[i % owners.length].publicKeys.masterIncomingViewingPublicKey,
121
+ ivpkM: owners[i % owners.length].publicKeys.masterIncomingViewingPublicKey,
120
122
  index: BigInt(i),
121
123
  }),
122
124
  );
123
- });
124
125
 
125
- beforeEach(async () => {
126
126
  for (const owner of owners) {
127
127
  await database.addCompleteAddress(owner);
128
128
  }
129
129
  });
130
130
 
131
131
  it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
132
- await database.addNotes(notes);
133
- await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
132
+ await database.addNotes(notes, []);
133
+ await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
134
134
  });
135
135
 
136
136
  it.each(filteringTests)('stores notes one by one and retrieves notes', async (getFilter, getExpected) => {
137
137
  for (const note of notes) {
138
138
  await database.addNote(note);
139
139
  }
140
- await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
140
+ await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
141
141
  });
142
142
 
143
143
  it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => {
144
- await database.addNotes(notes);
144
+ await database.addNotes(notes, []);
145
145
 
146
146
  // Nullify all notes and use the same filter as other test cases
147
147
  for (const owner of owners) {
148
148
  const notesToNullify = notes.filter(note =>
149
- note.publicKey.equals(owner.publicKeys.masterIncomingViewingPublicKey),
149
+ note.ivpkM.equals(owner.publicKeys.masterIncomingViewingPublicKey),
150
150
  );
151
151
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
152
152
  await expect(
@@ -154,41 +154,41 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
154
154
  ).resolves.toEqual(notesToNullify);
155
155
  }
156
156
 
157
- await expect(database.getNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED })).resolves.toEqual(
158
- getExpected(),
159
- );
157
+ await expect(
158
+ database.getIncomingNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED }),
159
+ ).resolves.toEqual(getExpected());
160
160
  });
161
161
 
162
162
  it('skips nullified notes by default or when requesting active', async () => {
163
- await database.addNotes(notes);
163
+ await database.addNotes(notes, []);
164
164
 
165
165
  const notesToNullify = notes.filter(note =>
166
- note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
166
+ note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
167
167
  );
168
168
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
169
- await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
169
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].ivpkM)).resolves.toEqual(
170
170
  notesToNullify,
171
171
  );
172
172
 
173
- const actualNotesWithDefault = await database.getNotes({});
174
- const actualNotesWithActive = await database.getNotes({ status: NoteStatus.ACTIVE });
173
+ const actualNotesWithDefault = await database.getIncomingNotes({});
174
+ const actualNotesWithActive = await database.getIncomingNotes({ status: NoteStatus.ACTIVE });
175
175
 
176
176
  expect(actualNotesWithDefault).toEqual(actualNotesWithActive);
177
177
  expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note)));
178
178
  });
179
179
 
180
180
  it('returns active and nullified notes when requesting either', async () => {
181
- await database.addNotes(notes);
181
+ await database.addNotes(notes, []);
182
182
 
183
183
  const notesToNullify = notes.filter(note =>
184
- note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
184
+ note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
185
185
  );
186
186
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
187
- await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
187
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].ivpkM)).resolves.toEqual(
188
188
  notesToNullify,
189
189
  );
190
190
 
191
- const result = await database.getNotes({
191
+ const result = await database.getIncomingNotes({
192
192
  status: NoteStatus.ACTIVE_OR_NULLIFIED,
193
193
  });
194
194
 
@@ -198,6 +198,70 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
198
198
  });
199
199
  });
200
200
 
201
+ describe('outgoing notes', () => {
202
+ let owners: CompleteAddress[];
203
+ let contractAddresses: AztecAddress[];
204
+ let storageSlots: Fr[];
205
+ let notes: OutgoingNoteDao[];
206
+
207
+ const filteringTests: [() => OutgoingNotesFilter, () => OutgoingNoteDao[]][] = [
208
+ [() => ({}), () => notes],
209
+
210
+ [
211
+ () => ({ contractAddress: contractAddresses[0] }),
212
+ () => notes.filter(note => note.contractAddress.equals(contractAddresses[0])),
213
+ ],
214
+ [() => ({ contractAddress: AztecAddress.random() }), () => []],
215
+
216
+ [
217
+ () => ({ storageSlot: storageSlots[0] }),
218
+ () => notes.filter(note => note.storageSlot.equals(storageSlots[0])),
219
+ ],
220
+ [() => ({ storageSlot: Fr.random() }), () => []],
221
+
222
+ [() => ({ txHash: notes[0].txHash }), () => [notes[0]]],
223
+ [() => ({ txHash: randomTxHash() }), () => []],
224
+
225
+ [
226
+ () => ({ owner: owners[0].address }),
227
+ () => notes.filter(note => note.ovpkM.equals(owners[0].publicKeys.masterOutgoingViewingPublicKey)),
228
+ ],
229
+
230
+ [
231
+ () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }),
232
+ () =>
233
+ notes.filter(
234
+ note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]),
235
+ ),
236
+ ],
237
+ [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []],
238
+ ];
239
+
240
+ beforeEach(async () => {
241
+ owners = Array.from({ length: 2 }).map(() => CompleteAddress.random());
242
+ contractAddresses = Array.from({ length: 2 }).map(() => AztecAddress.random());
243
+ storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
244
+
245
+ notes = Array.from({ length: 10 }).map((_, i) =>
246
+ randomOutgoingNoteDao({
247
+ contractAddress: contractAddresses[i % contractAddresses.length],
248
+ storageSlot: storageSlots[i % storageSlots.length],
249
+ ovpkM: owners[i % owners.length].publicKeys.masterOutgoingViewingPublicKey,
250
+ index: BigInt(i),
251
+ }),
252
+ );
253
+
254
+ for (const owner of owners) {
255
+ await database.addCompleteAddress(owner);
256
+ }
257
+ });
258
+
259
+ it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
260
+ await database.addNotes([], notes);
261
+ await expect(database.getOutgoingNotes(getFilter())).resolves.toEqual(getExpected());
262
+ });
263
+ });
264
+
201
265
  describe('block header', () => {
202
266
  it('stores and retrieves the block header', async () => {
203
267
  const header = makeHeader(randomInt(1000), INITIAL_L2_BLOCK_NUM);