@aztec/pxe 0.63.1 → 0.65.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.
- package/dest/database/contracts/contract_artifact_db.d.ts +1 -0
- package/dest/database/contracts/contract_artifact_db.d.ts.map +1 -1
- package/dest/database/incoming_note_dao.d.ts +10 -1
- package/dest/database/incoming_note_dao.d.ts.map +1 -1
- package/dest/database/incoming_note_dao.js +18 -5
- package/dest/database/kv_pxe_database.d.ts +6 -3
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +123 -22
- package/dest/database/outgoing_note_dao.d.ts +10 -1
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +18 -5
- package/dest/database/pxe_database.d.ts +22 -5
- package/dest/database/pxe_database.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.js +65 -16
- package/dest/kernel_oracle/index.js +2 -2
- package/dest/note_decryption_utils/produce_note_daos.d.ts +1 -1
- package/dest/note_decryption_utils/produce_note_daos.d.ts.map +1 -1
- package/dest/note_decryption_utils/produce_note_daos.js +5 -5
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +1 -1
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +1 -1
- package/dest/note_decryption_utils/produce_note_daos_for_key.js +3 -3
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +6 -3
- package/dest/pxe_service/pxe_service.d.ts +5 -4
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +51 -25
- package/dest/simulator_oracle/index.d.ts +8 -0
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +67 -10
- package/dest/synchronizer/synchronizer.d.ts +13 -28
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +42 -64
- package/package.json +14 -14
- package/src/database/contracts/contract_artifact_db.ts +1 -0
- package/src/database/incoming_note_dao.ts +46 -1
- package/src/database/kv_pxe_database.ts +148 -23
- package/src/database/outgoing_note_dao.ts +43 -1
- package/src/database/pxe_database.ts +25 -5
- package/src/database/pxe_database_test_suite.ts +79 -17
- package/src/kernel_oracle/index.ts +1 -1
- package/src/note_decryption_utils/produce_note_daos.ts +8 -0
- package/src/note_decryption_utils/produce_note_daos_for_key.ts +5 -1
- package/src/pxe_service/create_pxe_service.ts +7 -4
- package/src/pxe_service/pxe_service.ts +109 -72
- package/src/simulator_oracle/index.ts +95 -17
- package/src/synchronizer/synchronizer.ts +60 -71
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type InBlock,
|
|
3
|
+
type IncomingNotesFilter,
|
|
4
|
+
MerkleTreeId,
|
|
5
|
+
NoteStatus,
|
|
6
|
+
type OutgoingNotesFilter,
|
|
7
|
+
} from '@aztec/circuit-types';
|
|
2
8
|
import {
|
|
3
9
|
AztecAddress,
|
|
4
10
|
CompleteAddress,
|
|
@@ -7,9 +13,8 @@ import {
|
|
|
7
13
|
type IndexedTaggingSecret,
|
|
8
14
|
type PublicKey,
|
|
9
15
|
SerializableContractInstance,
|
|
10
|
-
computePoint,
|
|
11
16
|
} from '@aztec/circuits.js';
|
|
12
|
-
import { type ContractArtifact } from '@aztec/foundation/abi';
|
|
17
|
+
import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi';
|
|
13
18
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
14
19
|
import { Fr } from '@aztec/foundation/fields';
|
|
15
20
|
import {
|
|
@@ -39,11 +44,14 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
39
44
|
#notes: AztecMap<string, Buffer>;
|
|
40
45
|
#nullifiedNotes: AztecMap<string, Buffer>;
|
|
41
46
|
#nullifierToNoteId: AztecMap<string, string>;
|
|
47
|
+
#nullifiersByBlockNumber: AztecMultiMap<number, string>;
|
|
42
48
|
|
|
49
|
+
#nullifiedNotesToScope: AztecMultiMap<string, string>;
|
|
43
50
|
#nullifiedNotesByContract: AztecMultiMap<string, string>;
|
|
44
51
|
#nullifiedNotesByStorageSlot: AztecMultiMap<string, string>;
|
|
45
52
|
#nullifiedNotesByTxHash: AztecMultiMap<string, string>;
|
|
46
53
|
#nullifiedNotesByAddressPoint: AztecMultiMap<string, string>;
|
|
54
|
+
#nullifiedNotesByNullifier: AztecMap<string, string>;
|
|
47
55
|
#syncedBlockPerPublicKey: AztecMap<string, number>;
|
|
48
56
|
#contractArtifacts: AztecMap<string, Buffer>;
|
|
49
57
|
#contractInstances: AztecMap<string, Buffer>;
|
|
@@ -56,6 +64,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
56
64
|
#outgoingNotesByOvpkM: AztecMultiMap<string, string>;
|
|
57
65
|
|
|
58
66
|
#scopes: AztecSet<string>;
|
|
67
|
+
#notesToScope: AztecMultiMap<string, string>;
|
|
59
68
|
#notesByContractAndScope: Map<string, AztecMultiMap<string, string>>;
|
|
60
69
|
#notesByStorageSlotAndScope: Map<string, AztecMultiMap<string, string>>;
|
|
61
70
|
#notesByTxHashAndScope: Map<string, AztecMultiMap<string, string>>;
|
|
@@ -87,11 +96,14 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
87
96
|
this.#notes = db.openMap('notes');
|
|
88
97
|
this.#nullifiedNotes = db.openMap('nullified_notes');
|
|
89
98
|
this.#nullifierToNoteId = db.openMap('nullifier_to_note');
|
|
99
|
+
this.#nullifiersByBlockNumber = db.openMultiMap('nullifier_to_block_number');
|
|
90
100
|
|
|
101
|
+
this.#nullifiedNotesToScope = db.openMultiMap('nullified_notes_to_scope');
|
|
91
102
|
this.#nullifiedNotesByContract = db.openMultiMap('nullified_notes_by_contract');
|
|
92
103
|
this.#nullifiedNotesByStorageSlot = db.openMultiMap('nullified_notes_by_storage_slot');
|
|
93
104
|
this.#nullifiedNotesByTxHash = db.openMultiMap('nullified_notes_by_tx_hash');
|
|
94
105
|
this.#nullifiedNotesByAddressPoint = db.openMultiMap('nullified_notes_by_address_point');
|
|
106
|
+
this.#nullifiedNotesByNullifier = db.openMap('nullified_notes_by_nullifier');
|
|
95
107
|
|
|
96
108
|
this.#outgoingNotes = db.openMap('outgoing_notes');
|
|
97
109
|
this.#outgoingNotesByContract = db.openMultiMap('outgoing_notes_by_contract');
|
|
@@ -100,6 +112,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
100
112
|
this.#outgoingNotesByOvpkM = db.openMultiMap('outgoing_notes_by_ovpk_m');
|
|
101
113
|
|
|
102
114
|
this.#scopes = db.openSet('scopes');
|
|
115
|
+
this.#notesToScope = db.openMultiMap('notes_to_scope');
|
|
103
116
|
this.#notesByContractAndScope = new Map<string, AztecMultiMap<string, string>>();
|
|
104
117
|
this.#notesByStorageSlotAndScope = new Map<string, AztecMultiMap<string, string>>();
|
|
105
118
|
this.#notesByTxHashAndScope = new Map<string, AztecMultiMap<string, string>>();
|
|
@@ -128,6 +141,19 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
public async addContractArtifact(id: Fr, contract: ContractArtifact): Promise<void> {
|
|
144
|
+
const privateSelectors = contract.functions
|
|
145
|
+
.filter(functionArtifact => functionArtifact.functionType === FunctionType.PRIVATE)
|
|
146
|
+
.map(privateFunctionArtifact =>
|
|
147
|
+
FunctionSelector.fromNameAndParameters(
|
|
148
|
+
privateFunctionArtifact.name,
|
|
149
|
+
privateFunctionArtifact.parameters,
|
|
150
|
+
).toString(),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (privateSelectors.length !== new Set(privateSelectors).size) {
|
|
154
|
+
throw new Error('Repeated function selectors of private functions');
|
|
155
|
+
}
|
|
156
|
+
|
|
131
157
|
await this.#contractArtifacts.set(id.toString(), contractArtifactToBuffer(contract));
|
|
132
158
|
}
|
|
133
159
|
|
|
@@ -195,6 +221,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
195
221
|
// Had we stored them by their nullifier, they would be returned in random order
|
|
196
222
|
const noteIndex = toBufferBE(dao.index, 32).toString('hex');
|
|
197
223
|
void this.#notes.set(noteIndex, dao.toBuffer());
|
|
224
|
+
void this.#notesToScope.set(noteIndex, scope.toString());
|
|
198
225
|
void this.#nullifierToNoteId.set(dao.siloedNullifier.toString(), noteIndex);
|
|
199
226
|
|
|
200
227
|
void this.#notesByContractAndScope.get(scope.toString())!.set(dao.contractAddress.toString(), noteIndex);
|
|
@@ -214,8 +241,92 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
214
241
|
});
|
|
215
242
|
}
|
|
216
243
|
|
|
244
|
+
public removeNotesAfter(blockNumber: number): Promise<void> {
|
|
245
|
+
return this.db.transaction(() => {
|
|
246
|
+
for (const note of this.#notes.values()) {
|
|
247
|
+
const noteDao = IncomingNoteDao.fromBuffer(note);
|
|
248
|
+
if (noteDao.l2BlockNumber > blockNumber) {
|
|
249
|
+
const noteIndex = toBufferBE(noteDao.index, 32).toString('hex');
|
|
250
|
+
void this.#notes.delete(noteIndex);
|
|
251
|
+
void this.#notesToScope.delete(noteIndex);
|
|
252
|
+
void this.#nullifierToNoteId.delete(noteDao.siloedNullifier.toString());
|
|
253
|
+
for (const scope of this.#scopes.entries()) {
|
|
254
|
+
void this.#notesByAddressPointAndScope.get(scope)!.deleteValue(noteDao.addressPoint.toString(), noteIndex);
|
|
255
|
+
void this.#notesByTxHashAndScope.get(scope)!.deleteValue(noteDao.txHash.toString(), noteIndex);
|
|
256
|
+
void this.#notesByContractAndScope.get(scope)!.deleteValue(noteDao.contractAddress.toString(), noteIndex);
|
|
257
|
+
void this.#notesByStorageSlotAndScope.get(scope)!.deleteValue(noteDao.storageSlot.toString(), noteIndex);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
for (const note of this.#outgoingNotes.values()) {
|
|
263
|
+
const noteDao = OutgoingNoteDao.fromBuffer(note);
|
|
264
|
+
if (noteDao.l2BlockNumber > blockNumber) {
|
|
265
|
+
const noteIndex = toBufferBE(noteDao.index, 32).toString('hex');
|
|
266
|
+
void this.#outgoingNotes.delete(noteIndex);
|
|
267
|
+
void this.#outgoingNotesByContract.deleteValue(noteDao.contractAddress.toString(), noteIndex);
|
|
268
|
+
void this.#outgoingNotesByStorageSlot.deleteValue(noteDao.storageSlot.toString(), noteIndex);
|
|
269
|
+
void this.#outgoingNotesByTxHash.deleteValue(noteDao.txHash.toString(), noteIndex);
|
|
270
|
+
void this.#outgoingNotesByOvpkM.deleteValue(noteDao.ovpkM.toString(), noteIndex);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
public async unnullifyNotesAfter(blockNumber: number): Promise<void> {
|
|
277
|
+
const nullifiersToUndo: string[] = [];
|
|
278
|
+
const currentBlockNumber = blockNumber + 1;
|
|
279
|
+
const maxBlockNumber = this.getBlockNumber() ?? currentBlockNumber;
|
|
280
|
+
for (let i = currentBlockNumber; i <= maxBlockNumber; i++) {
|
|
281
|
+
nullifiersToUndo.push(...this.#nullifiersByBlockNumber.getValues(i));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const notesIndexesToReinsert = await this.db.transaction(() =>
|
|
285
|
+
nullifiersToUndo.map(nullifier => this.#nullifiedNotesByNullifier.get(nullifier)),
|
|
286
|
+
);
|
|
287
|
+
const nullifiedNoteBuffers = await this.db.transaction(() => {
|
|
288
|
+
return notesIndexesToReinsert
|
|
289
|
+
.filter(noteIndex => noteIndex != undefined)
|
|
290
|
+
.map(noteIndex => this.#nullifiedNotes.get(noteIndex!));
|
|
291
|
+
});
|
|
292
|
+
const noteDaos = nullifiedNoteBuffers
|
|
293
|
+
.filter(buffer => buffer != undefined)
|
|
294
|
+
.map(buffer => IncomingNoteDao.fromBuffer(buffer!));
|
|
295
|
+
|
|
296
|
+
await this.db.transaction(() => {
|
|
297
|
+
for (const dao of noteDaos) {
|
|
298
|
+
const noteIndex = toBufferBE(dao.index, 32).toString('hex');
|
|
299
|
+
void this.#notes.set(noteIndex, dao.toBuffer());
|
|
300
|
+
void this.#nullifierToNoteId.set(dao.siloedNullifier.toString(), noteIndex);
|
|
301
|
+
|
|
302
|
+
let scopes = Array.from(this.#nullifiedNotesToScope.getValues(noteIndex) ?? []);
|
|
303
|
+
|
|
304
|
+
if (scopes.length === 0) {
|
|
305
|
+
scopes = [new AztecAddress(dao.addressPoint.x).toString()];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const scope of scopes) {
|
|
309
|
+
void this.#notesByContractAndScope.get(scope)!.set(dao.contractAddress.toString(), noteIndex);
|
|
310
|
+
void this.#notesByStorageSlotAndScope.get(scope)!.set(dao.storageSlot.toString(), noteIndex);
|
|
311
|
+
void this.#notesByTxHashAndScope.get(scope)!.set(dao.txHash.toString(), noteIndex);
|
|
312
|
+
void this.#notesByAddressPointAndScope.get(scope)!.set(dao.addressPoint.toString(), noteIndex);
|
|
313
|
+
void this.#notesToScope.set(noteIndex, scope);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
void this.#nullifiedNotes.delete(noteIndex);
|
|
317
|
+
void this.#nullifiedNotesToScope.delete(noteIndex);
|
|
318
|
+
void this.#nullifiersByBlockNumber.deleteValue(dao.l2BlockNumber, dao.siloedNullifier.toString());
|
|
319
|
+
void this.#nullifiedNotesByContract.deleteValue(dao.contractAddress.toString(), noteIndex);
|
|
320
|
+
void this.#nullifiedNotesByStorageSlot.deleteValue(dao.storageSlot.toString(), noteIndex);
|
|
321
|
+
void this.#nullifiedNotesByTxHash.deleteValue(dao.txHash.toString(), noteIndex);
|
|
322
|
+
void this.#nullifiedNotesByAddressPoint.deleteValue(dao.addressPoint.toString(), noteIndex);
|
|
323
|
+
void this.#nullifiedNotesByNullifier.delete(dao.siloedNullifier.toString());
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
217
328
|
getIncomingNotes(filter: IncomingNotesFilter): Promise<IncomingNoteDao[]> {
|
|
218
|
-
const publicKey: PublicKey | undefined = filter.owner ?
|
|
329
|
+
const publicKey: PublicKey | undefined = filter.owner ? filter.owner.toAddressPoint() : undefined;
|
|
219
330
|
|
|
220
331
|
filter.status = filter.status ?? NoteStatus.ACTIVE;
|
|
221
332
|
|
|
@@ -350,7 +461,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
350
461
|
return Promise.resolve(notes);
|
|
351
462
|
}
|
|
352
463
|
|
|
353
|
-
removeNullifiedNotes(nullifiers: Fr[], accountAddressPoint: PublicKey): Promise<IncomingNoteDao[]> {
|
|
464
|
+
removeNullifiedNotes(nullifiers: InBlock<Fr>[], accountAddressPoint: PublicKey): Promise<IncomingNoteDao[]> {
|
|
354
465
|
if (nullifiers.length === 0) {
|
|
355
466
|
return Promise.resolve([]);
|
|
356
467
|
}
|
|
@@ -358,7 +469,8 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
358
469
|
return this.#db.transaction(() => {
|
|
359
470
|
const nullifiedNotes: IncomingNoteDao[] = [];
|
|
360
471
|
|
|
361
|
-
for (const
|
|
472
|
+
for (const blockScopedNullifier of nullifiers) {
|
|
473
|
+
const { data: nullifier, l2BlockNumber: blockNumber } = blockScopedNullifier;
|
|
362
474
|
const noteIndex = this.#nullifierToNoteId.get(nullifier.toString());
|
|
363
475
|
if (!noteIndex) {
|
|
364
476
|
continue;
|
|
@@ -370,7 +482,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
370
482
|
// note doesn't exist. Maybe it got nullified already
|
|
371
483
|
continue;
|
|
372
484
|
}
|
|
373
|
-
|
|
485
|
+
const noteScopes = this.#notesToScope.getValues(noteIndex) ?? [];
|
|
374
486
|
const note = IncomingNoteDao.fromBuffer(noteBuffer);
|
|
375
487
|
if (!note.addressPoint.equals(accountAddressPoint)) {
|
|
376
488
|
// tried to nullify someone else's note
|
|
@@ -380,19 +492,27 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
380
492
|
nullifiedNotes.push(note);
|
|
381
493
|
|
|
382
494
|
void this.#notes.delete(noteIndex);
|
|
495
|
+
void this.#notesToScope.delete(noteIndex);
|
|
383
496
|
|
|
384
|
-
for (const scope
|
|
497
|
+
for (const scope of this.#scopes.entries()) {
|
|
385
498
|
void this.#notesByAddressPointAndScope.get(scope)!.deleteValue(accountAddressPoint.toString(), noteIndex);
|
|
386
499
|
void this.#notesByTxHashAndScope.get(scope)!.deleteValue(note.txHash.toString(), noteIndex);
|
|
387
500
|
void this.#notesByContractAndScope.get(scope)!.deleteValue(note.contractAddress.toString(), noteIndex);
|
|
388
501
|
void this.#notesByStorageSlotAndScope.get(scope)!.deleteValue(note.storageSlot.toString(), noteIndex);
|
|
389
502
|
}
|
|
390
503
|
|
|
504
|
+
if (noteScopes !== undefined) {
|
|
505
|
+
for (const scope of noteScopes) {
|
|
506
|
+
void this.#nullifiedNotesToScope.set(noteIndex, scope);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
391
509
|
void this.#nullifiedNotes.set(noteIndex, note.toBuffer());
|
|
510
|
+
void this.#nullifiersByBlockNumber.set(blockNumber, nullifier.toString());
|
|
392
511
|
void this.#nullifiedNotesByContract.set(note.contractAddress.toString(), noteIndex);
|
|
393
512
|
void this.#nullifiedNotesByStorageSlot.set(note.storageSlot.toString(), noteIndex);
|
|
394
513
|
void this.#nullifiedNotesByTxHash.set(note.txHash.toString(), noteIndex);
|
|
395
514
|
void this.#nullifiedNotesByAddressPoint.set(note.addressPoint.toString(), noteIndex);
|
|
515
|
+
void this.#nullifiedNotesByNullifier.set(nullifier.toString(), noteIndex);
|
|
396
516
|
|
|
397
517
|
void this.#nullifierToNoteId.delete(nullifier.toString());
|
|
398
518
|
}
|
|
@@ -548,25 +668,19 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
548
668
|
return incomingNotesSize + outgoingNotesSize + treeRootsSize + authWitsSize + addressesSize;
|
|
549
669
|
}
|
|
550
670
|
|
|
551
|
-
async
|
|
552
|
-
await this.#
|
|
671
|
+
async setTaggingSecretsIndexesAsSender(indexedSecrets: IndexedTaggingSecret[]): Promise<void> {
|
|
672
|
+
await this.#setTaggingSecretsIndexes(indexedSecrets, this.#taggingSecretIndexesForSenders);
|
|
553
673
|
}
|
|
554
674
|
|
|
555
|
-
async
|
|
556
|
-
|
|
557
|
-
await this.db.transaction(() => {
|
|
558
|
-
indexes.forEach((taggingSecretIndex, listIndex) => {
|
|
559
|
-
const nextIndex = taggingSecretIndex + 1;
|
|
560
|
-
void storageMap.set(appTaggingSecrets[listIndex].toString(), nextIndex);
|
|
561
|
-
});
|
|
562
|
-
});
|
|
675
|
+
async setTaggingSecretsIndexesAsRecipient(indexedSecrets: IndexedTaggingSecret[]): Promise<void> {
|
|
676
|
+
await this.#setTaggingSecretsIndexes(indexedSecrets, this.#taggingSecretIndexesForRecipients);
|
|
563
677
|
}
|
|
564
678
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
indexedSecrets.forEach(
|
|
568
|
-
void
|
|
569
|
-
|
|
679
|
+
#setTaggingSecretsIndexes(indexedSecrets: IndexedTaggingSecret[], storageMap: AztecMap<string, number>) {
|
|
680
|
+
return this.db.transaction(() => {
|
|
681
|
+
indexedSecrets.forEach(
|
|
682
|
+
indexedSecret => void storageMap.set(indexedSecret.secret.toString(), indexedSecret.index),
|
|
683
|
+
);
|
|
570
684
|
});
|
|
571
685
|
}
|
|
572
686
|
|
|
@@ -581,4 +695,15 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
581
695
|
#getTaggingSecretsIndexes(appTaggingSecrets: Fr[], storageMap: AztecMap<string, number>): Promise<number[]> {
|
|
582
696
|
return this.db.transaction(() => appTaggingSecrets.map(secret => storageMap.get(`${secret.toString()}`) ?? 0));
|
|
583
697
|
}
|
|
698
|
+
|
|
699
|
+
async resetNoteSyncData(): Promise<void> {
|
|
700
|
+
await this.db.transaction(() => {
|
|
701
|
+
for (const recipient of this.#taggingSecretIndexesForRecipients.keys()) {
|
|
702
|
+
void this.#taggingSecretIndexesForRecipients.delete(recipient);
|
|
703
|
+
}
|
|
704
|
+
for (const sender of this.#taggingSecretIndexesForSenders.keys()) {
|
|
705
|
+
void this.#taggingSecretIndexesForSenders.delete(sender);
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
}
|
|
584
709
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type L1NotePayload, Note, TxHash } from '@aztec/circuit-types';
|
|
1
|
+
import { type L1NotePayload, Note, TxHash, randomTxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { NoteSelector } from '@aztec/foundation/abi';
|
|
4
4
|
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
|
|
@@ -21,6 +21,10 @@ export class OutgoingNoteDao {
|
|
|
21
21
|
public noteTypeId: NoteSelector,
|
|
22
22
|
/** The hash of the tx the note was created in. */
|
|
23
23
|
public txHash: TxHash,
|
|
24
|
+
/** The L2 block number in which the tx with this note was included. */
|
|
25
|
+
public l2BlockNumber: number,
|
|
26
|
+
/** The L2 block hash in which the tx with this note was included. */
|
|
27
|
+
public l2BlockHash: string,
|
|
24
28
|
/** The nonce of the note. */
|
|
25
29
|
public nonce: Fr,
|
|
26
30
|
/**
|
|
@@ -38,6 +42,8 @@ export class OutgoingNoteDao {
|
|
|
38
42
|
note: Note,
|
|
39
43
|
payload: L1NotePayload,
|
|
40
44
|
noteInfo: NoteInfo,
|
|
45
|
+
l2BlockNumber: number,
|
|
46
|
+
l2BlockHash: string,
|
|
41
47
|
dataStartIndexForTx: number,
|
|
42
48
|
ovpkM: PublicKey,
|
|
43
49
|
) {
|
|
@@ -48,6 +54,8 @@ export class OutgoingNoteDao {
|
|
|
48
54
|
payload.storageSlot,
|
|
49
55
|
payload.noteTypeId,
|
|
50
56
|
noteInfo.txHash,
|
|
57
|
+
l2BlockNumber,
|
|
58
|
+
l2BlockHash,
|
|
51
59
|
noteInfo.nonce,
|
|
52
60
|
noteInfo.noteHash,
|
|
53
61
|
noteHashIndexInTheWholeTree,
|
|
@@ -62,6 +70,8 @@ export class OutgoingNoteDao {
|
|
|
62
70
|
this.storageSlot,
|
|
63
71
|
this.noteTypeId,
|
|
64
72
|
this.txHash.buffer,
|
|
73
|
+
this.l2BlockNumber,
|
|
74
|
+
Fr.fromString(this.l2BlockHash),
|
|
65
75
|
this.nonce,
|
|
66
76
|
this.noteHash,
|
|
67
77
|
this.index,
|
|
@@ -76,6 +86,8 @@ export class OutgoingNoteDao {
|
|
|
76
86
|
const storageSlot = Fr.fromBuffer(reader);
|
|
77
87
|
const noteTypeId = reader.readObject(NoteSelector);
|
|
78
88
|
const txHash = new TxHash(reader.readBytes(TxHash.SIZE));
|
|
89
|
+
const l2BlockNumber = reader.readNumber();
|
|
90
|
+
const l2BlockHash = Fr.fromBuffer(reader).toString();
|
|
79
91
|
const nonce = Fr.fromBuffer(reader);
|
|
80
92
|
const noteHash = Fr.fromBuffer(reader);
|
|
81
93
|
const index = toBigIntBE(reader.readBytes(32));
|
|
@@ -87,6 +99,8 @@ export class OutgoingNoteDao {
|
|
|
87
99
|
storageSlot,
|
|
88
100
|
noteTypeId,
|
|
89
101
|
txHash,
|
|
102
|
+
l2BlockNumber,
|
|
103
|
+
l2BlockHash,
|
|
90
104
|
nonce,
|
|
91
105
|
noteHash,
|
|
92
106
|
index,
|
|
@@ -111,4 +125,32 @@ export class OutgoingNoteDao {
|
|
|
111
125
|
const noteSize = 4 + this.note.items.length * Fr.SIZE_IN_BYTES;
|
|
112
126
|
return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 2 + TxHash.SIZE + Point.SIZE_IN_BYTES;
|
|
113
127
|
}
|
|
128
|
+
|
|
129
|
+
static random({
|
|
130
|
+
note = Note.random(),
|
|
131
|
+
contractAddress = AztecAddress.random(),
|
|
132
|
+
txHash = randomTxHash(),
|
|
133
|
+
storageSlot = Fr.random(),
|
|
134
|
+
noteTypeId = NoteSelector.random(),
|
|
135
|
+
nonce = Fr.random(),
|
|
136
|
+
l2BlockNumber = Math.floor(Math.random() * 1000),
|
|
137
|
+
l2BlockHash = Fr.random().toString(),
|
|
138
|
+
noteHash = Fr.random(),
|
|
139
|
+
index = Fr.random().toBigInt(),
|
|
140
|
+
ovpkM = Point.random(),
|
|
141
|
+
}: Partial<OutgoingNoteDao> = {}) {
|
|
142
|
+
return new OutgoingNoteDao(
|
|
143
|
+
note,
|
|
144
|
+
contractAddress,
|
|
145
|
+
storageSlot,
|
|
146
|
+
noteTypeId,
|
|
147
|
+
txHash,
|
|
148
|
+
l2BlockNumber,
|
|
149
|
+
l2BlockHash,
|
|
150
|
+
nonce,
|
|
151
|
+
noteHash,
|
|
152
|
+
index,
|
|
153
|
+
ovpkM,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
114
156
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IncomingNotesFilter, type OutgoingNotesFilter } from '@aztec/circuit-types';
|
|
1
|
+
import { type InBlock, type IncomingNotesFilter, type OutgoingNotesFilter } from '@aztec/circuit-types';
|
|
2
2
|
import {
|
|
3
3
|
type CompleteAddress,
|
|
4
4
|
type ContractInstanceWithAddress,
|
|
@@ -96,7 +96,7 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
96
96
|
* @param account - A PublicKey instance representing the account for which the records are being removed.
|
|
97
97
|
* @returns Removed notes.
|
|
98
98
|
*/
|
|
99
|
-
removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise<IncomingNoteDao[]>;
|
|
99
|
+
removeNullifiedNotes(nullifiers: InBlock<Fr>[], account: PublicKey): Promise<IncomingNoteDao[]>;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Gets the most recently processed block number.
|
|
@@ -202,11 +202,11 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
202
202
|
getTaggingSecretsIndexesAsSender(appTaggingSecrets: Fr[]): Promise<number[]>;
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
*
|
|
206
|
-
* To be used when the generated tags have been
|
|
205
|
+
* Sets the index for the provided app siloed tagging secrets
|
|
206
|
+
* To be used when the generated tags have been "seen" as a sender
|
|
207
207
|
* @param appTaggingSecrets - The app siloed tagging secrets.
|
|
208
208
|
*/
|
|
209
|
-
|
|
209
|
+
setTaggingSecretsIndexesAsSender(indexedTaggingSecrets: IndexedTaggingSecret[]): Promise<void>;
|
|
210
210
|
|
|
211
211
|
/**
|
|
212
212
|
* Sets the index for the provided app siloed tagging secrets
|
|
@@ -214,4 +214,24 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
214
214
|
* @param appTaggingSecrets - The app siloed tagging secrets.
|
|
215
215
|
*/
|
|
216
216
|
setTaggingSecretsIndexesAsRecipient(indexedTaggingSecrets: IndexedTaggingSecret[]): Promise<void>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Deletes all notes synched after this block number.
|
|
220
|
+
* @param blockNumber - All notes strictly after this block number are removed.
|
|
221
|
+
*/
|
|
222
|
+
removeNotesAfter(blockNumber: number): Promise<void>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Restores notes nullified after the given block.
|
|
226
|
+
* @param blockNumber - All nullifiers strictly after this block are removed.
|
|
227
|
+
*/
|
|
228
|
+
unnullifyNotesAfter(blockNumber: number): Promise<void>;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Resets the indexes used to sync notes to 0 for every sender and recipient, causing the next sync process to
|
|
232
|
+
* start from scratch, taking longer than usual.
|
|
233
|
+
* This can help fix desynchronization issues, including finding logs that had previously been overlooked, and
|
|
234
|
+
* is also required to deal with chain reorgs.
|
|
235
|
+
*/
|
|
236
|
+
resetNoteSyncData(): Promise<void>;
|
|
217
237
|
}
|
|
@@ -5,17 +5,16 @@ import {
|
|
|
5
5
|
INITIAL_L2_BLOCK_NUM,
|
|
6
6
|
PublicKeys,
|
|
7
7
|
SerializableContractInstance,
|
|
8
|
-
computePoint,
|
|
9
8
|
} from '@aztec/circuits.js';
|
|
10
9
|
import { makeHeader } from '@aztec/circuits.js/testing';
|
|
10
|
+
import { FunctionType } from '@aztec/foundation/abi';
|
|
11
11
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
12
12
|
import { Fr, Point } from '@aztec/foundation/fields';
|
|
13
13
|
import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking';
|
|
14
|
+
import { TestContractArtifact } from '@aztec/noir-contracts.js/Test';
|
|
14
15
|
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { type OutgoingNoteDao } from './outgoing_note_dao.js';
|
|
18
|
-
import { randomOutgoingNoteDao } from './outgoing_note_dao.test.js';
|
|
16
|
+
import { IncomingNoteDao } from './incoming_note_dao.js';
|
|
17
|
+
import { OutgoingNoteDao } from './outgoing_note_dao.js';
|
|
19
18
|
import { type PxeDatabase } from './pxe_database.js';
|
|
20
19
|
|
|
21
20
|
/**
|
|
@@ -102,7 +101,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
102
101
|
|
|
103
102
|
[
|
|
104
103
|
() => ({ owner: owners[0].address }),
|
|
105
|
-
() => notes.filter(note => note.addressPoint.equals(
|
|
104
|
+
() => notes.filter(note => note.addressPoint.equals(owners[0].address.toAddressPoint())),
|
|
106
105
|
],
|
|
107
106
|
|
|
108
107
|
[
|
|
@@ -121,11 +120,12 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
121
120
|
storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
|
|
122
121
|
|
|
123
122
|
notes = Array.from({ length: 10 }).map((_, i) =>
|
|
124
|
-
|
|
123
|
+
IncomingNoteDao.random({
|
|
125
124
|
contractAddress: contractAddresses[i % contractAddresses.length],
|
|
126
125
|
storageSlot: storageSlots[i % storageSlots.length],
|
|
127
|
-
addressPoint:
|
|
126
|
+
addressPoint: owners[i % owners.length].address.toAddressPoint(),
|
|
128
127
|
index: BigInt(i),
|
|
128
|
+
l2BlockNumber: i,
|
|
129
129
|
}),
|
|
130
130
|
);
|
|
131
131
|
|
|
@@ -156,9 +156,13 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
156
156
|
|
|
157
157
|
// Nullify all notes and use the same filter as other test cases
|
|
158
158
|
for (const owner of owners) {
|
|
159
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
160
|
-
const nullifiers = notesToNullify.map(note =>
|
|
161
|
-
|
|
159
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(owner.address.toAddressPoint()));
|
|
160
|
+
const nullifiers = notesToNullify.map(note => ({
|
|
161
|
+
data: note.siloedNullifier,
|
|
162
|
+
l2BlockNumber: note.l2BlockNumber,
|
|
163
|
+
l2BlockHash: note.l2BlockHash,
|
|
164
|
+
}));
|
|
165
|
+
await expect(database.removeNullifiedNotes(nullifiers, owner.address.toAddressPoint())).resolves.toEqual(
|
|
162
166
|
notesToNullify,
|
|
163
167
|
);
|
|
164
168
|
}
|
|
@@ -171,8 +175,12 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
171
175
|
it('skips nullified notes by default or when requesting active', async () => {
|
|
172
176
|
await database.addNotes(notes, []);
|
|
173
177
|
|
|
174
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
175
|
-
const nullifiers = notesToNullify.map(note =>
|
|
178
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(owners[0].address.toAddressPoint()));
|
|
179
|
+
const nullifiers = notesToNullify.map(note => ({
|
|
180
|
+
data: note.siloedNullifier,
|
|
181
|
+
l2BlockNumber: note.l2BlockNumber,
|
|
182
|
+
l2BlockHash: note.l2BlockHash,
|
|
183
|
+
}));
|
|
176
184
|
await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].addressPoint)).resolves.toEqual(
|
|
177
185
|
notesToNullify,
|
|
178
186
|
);
|
|
@@ -184,11 +192,35 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
184
192
|
expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note)));
|
|
185
193
|
});
|
|
186
194
|
|
|
195
|
+
it('handles note unnullification', async () => {
|
|
196
|
+
await database.setHeader(makeHeader(randomInt(1000), 100, 0 /** slot number */));
|
|
197
|
+
await database.addNotes(notes, []);
|
|
198
|
+
|
|
199
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(owners[0].address.toAddressPoint()));
|
|
200
|
+
const nullifiers = notesToNullify.map(note => ({
|
|
201
|
+
data: note.siloedNullifier,
|
|
202
|
+
l2BlockNumber: 99,
|
|
203
|
+
l2BlockHash: Fr.random().toString(),
|
|
204
|
+
}));
|
|
205
|
+
await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].addressPoint)).resolves.toEqual(
|
|
206
|
+
notesToNullify,
|
|
207
|
+
);
|
|
208
|
+
await expect(database.unnullifyNotesAfter(98)).resolves.toEqual(undefined);
|
|
209
|
+
|
|
210
|
+
const result = await database.getIncomingNotes({ status: NoteStatus.ACTIVE, owner: owners[0].address });
|
|
211
|
+
|
|
212
|
+
expect(result.sort()).toEqual([...notesToNullify].sort());
|
|
213
|
+
});
|
|
214
|
+
|
|
187
215
|
it('returns active and nullified notes when requesting either', async () => {
|
|
188
216
|
await database.addNotes(notes, []);
|
|
189
217
|
|
|
190
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
191
|
-
const nullifiers = notesToNullify.map(note =>
|
|
218
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(owners[0].address.toAddressPoint()));
|
|
219
|
+
const nullifiers = notesToNullify.map(note => ({
|
|
220
|
+
data: note.siloedNullifier,
|
|
221
|
+
l2BlockNumber: note.l2BlockNumber,
|
|
222
|
+
l2BlockHash: note.l2BlockHash,
|
|
223
|
+
}));
|
|
192
224
|
await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].addressPoint)).resolves.toEqual(
|
|
193
225
|
notesToNullify,
|
|
194
226
|
);
|
|
@@ -246,7 +278,16 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
246
278
|
).resolves.toEqual([notes[0]]);
|
|
247
279
|
|
|
248
280
|
await expect(
|
|
249
|
-
database.removeNullifiedNotes(
|
|
281
|
+
database.removeNullifiedNotes(
|
|
282
|
+
[
|
|
283
|
+
{
|
|
284
|
+
data: notes[0].siloedNullifier,
|
|
285
|
+
l2BlockHash: notes[0].l2BlockHash,
|
|
286
|
+
l2BlockNumber: notes[0].l2BlockNumber,
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
owners[0].address.toAddressPoint(),
|
|
290
|
+
),
|
|
250
291
|
).resolves.toEqual([notes[0]]);
|
|
251
292
|
|
|
252
293
|
await expect(
|
|
@@ -260,6 +301,14 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
260
301
|
}),
|
|
261
302
|
).resolves.toEqual([]);
|
|
262
303
|
});
|
|
304
|
+
|
|
305
|
+
it('removes notes after a given block', async () => {
|
|
306
|
+
await database.addNotes(notes, [], owners[0].address);
|
|
307
|
+
|
|
308
|
+
await database.removeNotesAfter(5);
|
|
309
|
+
const result = await database.getIncomingNotes({ scopes: [owners[0].address] });
|
|
310
|
+
expect(new Set(result)).toEqual(new Set(notes.slice(0, 6)));
|
|
311
|
+
});
|
|
263
312
|
});
|
|
264
313
|
|
|
265
314
|
describe('outgoing notes', () => {
|
|
@@ -307,7 +356,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
307
356
|
storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
|
|
308
357
|
|
|
309
358
|
notes = Array.from({ length: 10 }).map((_, i) =>
|
|
310
|
-
|
|
359
|
+
OutgoingNoteDao.random({
|
|
311
360
|
contractAddress: contractAddresses[i % contractAddresses.length],
|
|
312
361
|
storageSlot: storageSlots[i % storageSlots.length],
|
|
313
362
|
ovpkM: owners[i % owners.length].publicKeys.masterOutgoingViewingPublicKey,
|
|
@@ -391,6 +440,19 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
391
440
|
await expect(database.getContractArtifact(id)).resolves.toEqual(artifact);
|
|
392
441
|
});
|
|
393
442
|
|
|
443
|
+
it('does not store a contract artifact with a duplicate private function selector', async () => {
|
|
444
|
+
const artifact = TestContractArtifact;
|
|
445
|
+
const index = artifact.functions.findIndex(fn => fn.functionType === FunctionType.PRIVATE);
|
|
446
|
+
|
|
447
|
+
const copiedFn = structuredClone(artifact.functions[index]);
|
|
448
|
+
artifact.functions.push(copiedFn);
|
|
449
|
+
|
|
450
|
+
const id = Fr.random();
|
|
451
|
+
await expect(database.addContractArtifact(id, artifact)).rejects.toThrow(
|
|
452
|
+
'Repeated function selectors of private functions',
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
|
|
394
456
|
it('stores a contract instance', async () => {
|
|
395
457
|
const address = AztecAddress.random();
|
|
396
458
|
const instance = SerializableContractInstance.random().withAddress(address);
|
|
@@ -70,7 +70,7 @@ export class KernelOracle implements ProvingDataOracle {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
async getNoteHashTreeRoot(): Promise<Fr> {
|
|
73
|
-
const header = await this.node.
|
|
73
|
+
const header = await this.node.getBlockHeader(this.blockNumber);
|
|
74
74
|
return header.state.partial.noteHashTree.root;
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -34,6 +34,8 @@ export async function produceNoteDaos(
|
|
|
34
34
|
ovpkM: PublicKey | undefined,
|
|
35
35
|
payload: L1NotePayload,
|
|
36
36
|
txHash: TxHash,
|
|
37
|
+
l2BlockNumber: number,
|
|
38
|
+
l2BlockHash: string,
|
|
37
39
|
noteHashes: Fr[],
|
|
38
40
|
dataStartIndexForTx: number,
|
|
39
41
|
excludedIndices: Set<number>,
|
|
@@ -56,6 +58,8 @@ export async function produceNoteDaos(
|
|
|
56
58
|
addressPoint,
|
|
57
59
|
payload,
|
|
58
60
|
txHash,
|
|
61
|
+
l2BlockNumber,
|
|
62
|
+
l2BlockHash,
|
|
59
63
|
noteHashes,
|
|
60
64
|
dataStartIndexForTx,
|
|
61
65
|
excludedIndices,
|
|
@@ -74,6 +78,8 @@ export async function produceNoteDaos(
|
|
|
74
78
|
incomingNote.storageSlot,
|
|
75
79
|
incomingNote.noteTypeId,
|
|
76
80
|
incomingNote.txHash,
|
|
81
|
+
incomingNote.l2BlockNumber,
|
|
82
|
+
incomingNote.l2BlockHash,
|
|
77
83
|
incomingNote.nonce,
|
|
78
84
|
incomingNote.noteHash,
|
|
79
85
|
incomingNote.index,
|
|
@@ -86,6 +92,8 @@ export async function produceNoteDaos(
|
|
|
86
92
|
ovpkM,
|
|
87
93
|
payload,
|
|
88
94
|
txHash,
|
|
95
|
+
l2BlockNumber,
|
|
96
|
+
l2BlockHash,
|
|
89
97
|
noteHashes,
|
|
90
98
|
dataStartIndexForTx,
|
|
91
99
|
excludedIndices,
|