@aztec/pxe 0.42.0 → 0.44.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/deferred_note_dao.d.ts +5 -4
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +4 -3
- package/dest/database/incoming_note_dao.d.ts +74 -0
- package/dest/database/incoming_note_dao.d.ts.map +1 -0
- package/dest/database/incoming_note_dao.js +93 -0
- package/dest/database/index.d.ts +1 -0
- package/dest/database/index.d.ts.map +1 -1
- package/dest/database/index.js +2 -1
- package/dest/database/kv_pxe_database.d.ts +10 -7
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +149 -78
- package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +10 -14
- package/dest/database/outgoing_note_dao.d.ts.map +1 -0
- package/dest/database/outgoing_note_dao.js +84 -0
- package/dest/database/pxe_database.d.ts +21 -9
- 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 +71 -24
- package/dest/index.d.ts +3 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +4 -1
- package/dest/kernel_oracle/index.d.ts +1 -1
- package/dest/note_processor/note_processor.d.ts +23 -20
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +116 -76
- package/dest/note_processor/produce_note_dao.d.ts +13 -4
- package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
- package/dest/note_processor/produce_note_dao.js +88 -31
- package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
- package/dest/pxe_http/pxe_http_server.js +3 -1
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +3 -1
- package/dest/pxe_service/pxe_service.d.ts +9 -4
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +106 -28
- package/dest/simulator_oracle/index.js +2 -2
- package/dest/synchronizer/synchronizer.d.ts +2 -2
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +37 -36
- package/package.json +23 -15
- package/src/database/deferred_note_dao.ts +4 -3
- package/src/database/{note_dao.ts → incoming_note_dao.ts} +14 -10
- package/src/database/index.ts +1 -0
- package/src/database/kv_pxe_database.ts +127 -29
- package/src/database/outgoing_note_dao.ts +91 -0
- package/src/database/pxe_database.ts +23 -9
- package/src/database/pxe_database_test_suite.ts +93 -29
- package/src/index.ts +3 -0
- package/src/note_processor/note_processor.ts +190 -121
- package/src/note_processor/produce_note_dao.ts +164 -50
- package/src/pxe_http/pxe_http_server.ts +2 -0
- package/src/pxe_service/create_pxe_service.ts +2 -0
- package/src/pxe_service/pxe_service.ts +170 -42
- package/src/simulator_oracle/index.ts +1 -1
- package/src/synchronizer/synchronizer.ts +48 -52
- package/dest/database/note_dao.d.ts.map +0 -1
- package/dest/database/note_dao.js +0 -89
|
@@ -3,18 +3,22 @@ import {
|
|
|
3
3
|
type AztecNode,
|
|
4
4
|
EncryptedNoteTxL2Logs,
|
|
5
5
|
EncryptedTxL2Logs,
|
|
6
|
+
type EventMetadata,
|
|
6
7
|
ExtendedNote,
|
|
7
8
|
type FunctionCall,
|
|
8
9
|
type GetUnencryptedLogsResponse,
|
|
10
|
+
type IncomingNotesFilter,
|
|
11
|
+
L1EventPayload,
|
|
9
12
|
type L2Block,
|
|
10
13
|
type LogFilter,
|
|
11
14
|
MerkleTreeId,
|
|
12
|
-
type
|
|
15
|
+
type OutgoingNotesFilter,
|
|
13
16
|
type PXE,
|
|
14
17
|
type PXEInfo,
|
|
15
18
|
type ProofCreator,
|
|
16
19
|
SimulatedTx,
|
|
17
20
|
SimulationError,
|
|
21
|
+
TaggedLog,
|
|
18
22
|
Tx,
|
|
19
23
|
type TxEffect,
|
|
20
24
|
type TxExecutionRequest,
|
|
@@ -32,11 +36,11 @@ import {
|
|
|
32
36
|
} from '@aztec/circuits.js';
|
|
33
37
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
34
38
|
import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
|
|
35
|
-
import { type Fq, Fr } from '@aztec/foundation/fields';
|
|
39
|
+
import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
|
|
36
40
|
import { SerialQueue } from '@aztec/foundation/fifo';
|
|
37
41
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
38
42
|
import { type KeyStore } from '@aztec/key-store';
|
|
39
|
-
import {
|
|
43
|
+
import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
|
|
40
44
|
import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
|
|
41
45
|
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
|
|
42
46
|
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
|
|
@@ -57,10 +61,11 @@ import { type NodeInfo } from '@aztec/types/interfaces';
|
|
|
57
61
|
|
|
58
62
|
import { type PXEServiceConfig, getPackageInfo } from '../config/index.js';
|
|
59
63
|
import { ContractDataOracle } from '../contract_data_oracle/index.js';
|
|
64
|
+
import { IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
60
65
|
import { type PxeDatabase } from '../database/index.js';
|
|
61
|
-
import { NoteDao } from '../database/note_dao.js';
|
|
62
66
|
import { KernelOracle } from '../kernel_oracle/index.js';
|
|
63
67
|
import { KernelProver } from '../kernel_prover/kernel_prover.js';
|
|
68
|
+
import { TestProofCreator } from '../kernel_prover/test/test_circuit_prover.js';
|
|
64
69
|
import { getAcirSimulator } from '../simulator/index.js';
|
|
65
70
|
import { Synchronizer } from '../synchronizer/index.js';
|
|
66
71
|
|
|
@@ -77,6 +82,8 @@ export class PXEService implements PXE {
|
|
|
77
82
|
// ensures that state is not changed while simulating
|
|
78
83
|
private jobQueue = new SerialQueue();
|
|
79
84
|
|
|
85
|
+
private fakeProofCreator = new TestProofCreator();
|
|
86
|
+
|
|
80
87
|
constructor(
|
|
81
88
|
private keyStore: KeyStore,
|
|
82
89
|
private node: AztecNode,
|
|
@@ -121,11 +128,7 @@ export class PXEService implements PXE {
|
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
count++;
|
|
124
|
-
this.synchronizer.addAccount(
|
|
125
|
-
address.publicKeys.masterIncomingViewingPublicKey,
|
|
126
|
-
this.keyStore,
|
|
127
|
-
this.config.l2StartingBlock,
|
|
128
|
-
);
|
|
131
|
+
await this.synchronizer.addAccount(address.address, this.keyStore, this.config.l2StartingBlock);
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
if (count > 0) {
|
|
@@ -177,6 +180,10 @@ export class PXEService implements PXE {
|
|
|
177
180
|
return artifact && getContractClassFromArtifact(artifact);
|
|
178
181
|
}
|
|
179
182
|
|
|
183
|
+
public getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
|
|
184
|
+
return this.db.getContractArtifact(id);
|
|
185
|
+
}
|
|
186
|
+
|
|
180
187
|
public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
|
|
181
188
|
const accounts = await this.keyStore.getAccounts();
|
|
182
189
|
const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress);
|
|
@@ -184,10 +191,7 @@ export class PXEService implements PXE {
|
|
|
184
191
|
this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
|
|
185
192
|
return accountCompleteAddress;
|
|
186
193
|
} else {
|
|
187
|
-
|
|
188
|
-
accountCompleteAddress.address,
|
|
189
|
-
);
|
|
190
|
-
this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock);
|
|
194
|
+
await this.synchronizer.addAccount(accountCompleteAddress.address, this.keyStore, this.config.l2StartingBlock);
|
|
191
195
|
this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
|
|
192
196
|
this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
|
|
193
197
|
}
|
|
@@ -258,6 +262,7 @@ export class PXEService implements PXE {
|
|
|
258
262
|
);
|
|
259
263
|
}
|
|
260
264
|
await this.db.addContractArtifact(contractClassId, artifact);
|
|
265
|
+
await this.node.addContractArtifact(instance.address, artifact);
|
|
261
266
|
} else {
|
|
262
267
|
// Otherwise, make sure there is an artifact already registered for that class id
|
|
263
268
|
artifact = await this.db.getContractArtifact(instance.contractClassId);
|
|
@@ -284,19 +289,40 @@ export class PXEService implements PXE {
|
|
|
284
289
|
return await this.node.getPublicStorageAt(contract, slot);
|
|
285
290
|
}
|
|
286
291
|
|
|
287
|
-
public async
|
|
288
|
-
const noteDaos = await this.db.
|
|
292
|
+
public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
|
|
293
|
+
const noteDaos = await this.db.getIncomingNotes(filter);
|
|
289
294
|
|
|
290
|
-
// TODO(
|
|
291
|
-
// key
|
|
295
|
+
// TODO(#6531): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
|
|
296
|
+
// key rotation will affect this
|
|
292
297
|
const extendedNotes = noteDaos.map(async dao => {
|
|
293
298
|
let owner = filter.owner;
|
|
294
299
|
if (owner === undefined) {
|
|
295
300
|
const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
|
|
296
|
-
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.
|
|
301
|
+
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.ivpkM),
|
|
297
302
|
);
|
|
298
303
|
if (completeAddresses === undefined) {
|
|
299
|
-
throw new Error(`Cannot find complete address for
|
|
304
|
+
throw new Error(`Cannot find complete address for IvpkM ${dao.ivpkM.toString()}`);
|
|
305
|
+
}
|
|
306
|
+
owner = completeAddresses.address;
|
|
307
|
+
}
|
|
308
|
+
return new ExtendedNote(dao.note, owner, dao.contractAddress, dao.storageSlot, dao.noteTypeId, dao.txHash);
|
|
309
|
+
});
|
|
310
|
+
return Promise.all(extendedNotes);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public async getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]> {
|
|
314
|
+
const noteDaos = await this.db.getOutgoingNotes(filter);
|
|
315
|
+
|
|
316
|
+
// TODO(#6532): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
|
|
317
|
+
// key rotation will affect this
|
|
318
|
+
const extendedNotes = noteDaos.map(async dao => {
|
|
319
|
+
let owner = filter.owner;
|
|
320
|
+
if (owner === undefined) {
|
|
321
|
+
const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
|
|
322
|
+
address.publicKeys.masterOutgoingViewingPublicKey.equals(dao.ovpkM),
|
|
323
|
+
);
|
|
324
|
+
if (completeAddresses === undefined) {
|
|
325
|
+
throw new Error(`Cannot find complete address for OvpkM ${dao.ovpkM.toString()}`);
|
|
300
326
|
}
|
|
301
327
|
owner = completeAddresses.address;
|
|
302
328
|
}
|
|
@@ -317,13 +343,15 @@ export class PXEService implements PXE {
|
|
|
317
343
|
}
|
|
318
344
|
|
|
319
345
|
for (const nonce of nonces) {
|
|
320
|
-
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
346
|
+
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
347
|
+
await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
348
|
+
note.contractAddress,
|
|
349
|
+
nonce,
|
|
350
|
+
note.storageSlot,
|
|
351
|
+
note.noteTypeId,
|
|
352
|
+
true,
|
|
353
|
+
note.note,
|
|
354
|
+
);
|
|
327
355
|
|
|
328
356
|
const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
|
|
329
357
|
if (index === undefined) {
|
|
@@ -337,7 +365,7 @@ export class PXEService implements PXE {
|
|
|
337
365
|
}
|
|
338
366
|
|
|
339
367
|
await this.db.addNote(
|
|
340
|
-
new
|
|
368
|
+
new IncomingNoteDao(
|
|
341
369
|
note.note,
|
|
342
370
|
note.contractAddress,
|
|
343
371
|
note.storageSlot,
|
|
@@ -353,6 +381,54 @@ export class PXEService implements PXE {
|
|
|
353
381
|
}
|
|
354
382
|
}
|
|
355
383
|
|
|
384
|
+
public async addNullifiedNote(note: ExtendedNote) {
|
|
385
|
+
const owner = await this.db.getCompleteAddress(note.owner);
|
|
386
|
+
if (!owner) {
|
|
387
|
+
throw new Error(`Unknown account: ${note.owner.toString()}`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const nonces = await this.getNoteNonces(note);
|
|
391
|
+
if (nonces.length === 0) {
|
|
392
|
+
throw new Error(`Cannot find the note in tx: ${note.txHash}.`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (const nonce of nonces) {
|
|
396
|
+
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
397
|
+
await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
398
|
+
note.contractAddress,
|
|
399
|
+
nonce,
|
|
400
|
+
note.storageSlot,
|
|
401
|
+
note.noteTypeId,
|
|
402
|
+
false,
|
|
403
|
+
note.note,
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (!innerNullifier.equals(Fr.ZERO)) {
|
|
407
|
+
throw new Error('Unexpectedly received non-zero nullifier.');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
|
|
411
|
+
if (index === undefined) {
|
|
412
|
+
throw new Error('Note does not exist.');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
await this.db.addNullifiedNote(
|
|
416
|
+
new IncomingNoteDao(
|
|
417
|
+
note.note,
|
|
418
|
+
note.contractAddress,
|
|
419
|
+
note.storageSlot,
|
|
420
|
+
note.noteTypeId,
|
|
421
|
+
note.txHash,
|
|
422
|
+
nonce,
|
|
423
|
+
innerNoteHash,
|
|
424
|
+
Fr.ZERO, // We are not able to derive
|
|
425
|
+
index,
|
|
426
|
+
owner.publicKeys.masterIncomingViewingPublicKey,
|
|
427
|
+
),
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
356
432
|
/**
|
|
357
433
|
* Finds the nonce(s) for a given note.
|
|
358
434
|
* @param note - The note to find the nonces for.
|
|
@@ -372,11 +448,12 @@ export class PXEService implements PXE {
|
|
|
372
448
|
// Remove this once notes added from public also include nonces.
|
|
373
449
|
{
|
|
374
450
|
const publicNoteNonce = Fr.ZERO;
|
|
375
|
-
const { siloedNoteHash } = await this.simulator.
|
|
451
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
376
452
|
note.contractAddress,
|
|
377
453
|
publicNoteNonce,
|
|
378
454
|
note.storageSlot,
|
|
379
455
|
note.noteTypeId,
|
|
456
|
+
false,
|
|
380
457
|
note.note,
|
|
381
458
|
);
|
|
382
459
|
if (tx.noteHashes.some(hash => hash.equals(siloedNoteHash))) {
|
|
@@ -393,11 +470,12 @@ export class PXEService implements PXE {
|
|
|
393
470
|
}
|
|
394
471
|
|
|
395
472
|
const nonce = computeNoteHashNonce(firstNullifier, i);
|
|
396
|
-
const { siloedNoteHash } = await this.simulator.
|
|
473
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
397
474
|
note.contractAddress,
|
|
398
475
|
nonce,
|
|
399
476
|
note.storageSlot,
|
|
400
477
|
note.noteTypeId,
|
|
478
|
+
false,
|
|
401
479
|
note.note,
|
|
402
480
|
);
|
|
403
481
|
if (hash.equals(siloedNoteHash)) {
|
|
@@ -416,8 +494,14 @@ export class PXEService implements PXE {
|
|
|
416
494
|
return await this.node.getBlock(blockNumber);
|
|
417
495
|
}
|
|
418
496
|
|
|
419
|
-
public
|
|
420
|
-
return
|
|
497
|
+
public proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx> {
|
|
498
|
+
return this.jobQueue.put(async () => {
|
|
499
|
+
const simulatedTx = await this.#simulateAndProve(txRequest, this.proofCreator, undefined);
|
|
500
|
+
if (simulatePublic) {
|
|
501
|
+
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
|
|
502
|
+
}
|
|
503
|
+
return simulatedTx.tx;
|
|
504
|
+
});
|
|
421
505
|
}
|
|
422
506
|
|
|
423
507
|
public async simulateTx(
|
|
@@ -426,16 +510,15 @@ export class PXEService implements PXE {
|
|
|
426
510
|
msgSender: AztecAddress | undefined = undefined,
|
|
427
511
|
): Promise<SimulatedTx> {
|
|
428
512
|
return await this.jobQueue.put(async () => {
|
|
429
|
-
const simulatedTx = await this.#simulateAndProve(txRequest, msgSender);
|
|
430
|
-
// We log only if the msgSender is undefined, as simulating with a different msgSender
|
|
431
|
-
// is unlikely to be a real transaction, and likely to be only used to read data.
|
|
432
|
-
// Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
|
|
433
|
-
// If we log, the `getTxHash` function will throw.
|
|
434
|
-
|
|
513
|
+
const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
|
|
435
514
|
if (simulatePublic) {
|
|
436
515
|
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
|
|
437
516
|
}
|
|
438
517
|
|
|
518
|
+
// We log only if the msgSender is undefined, as simulating with a different msgSender
|
|
519
|
+
// is unlikely to be a real transaction, and likely to be only used to read data.
|
|
520
|
+
// Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
|
|
521
|
+
// If we log, the `getTxHash` function will throw.
|
|
439
522
|
if (!msgSender) {
|
|
440
523
|
this.log.info(`Executed local simulation for ${simulatedTx.tx.getTxHash()}`);
|
|
441
524
|
}
|
|
@@ -539,7 +622,7 @@ export class PXEService implements PXE {
|
|
|
539
622
|
return Promise.resolve({
|
|
540
623
|
pxeVersion: this.packageVersion,
|
|
541
624
|
protocolContractAddresses: {
|
|
542
|
-
classRegisterer:
|
|
625
|
+
classRegisterer: ClassRegistererAddress,
|
|
543
626
|
gasToken: getCanonicalGasToken().address,
|
|
544
627
|
instanceDeployer: getCanonicalInstanceDeployer().address,
|
|
545
628
|
keyRegistry: getCanonicalKeyRegistryAddress(),
|
|
@@ -652,18 +735,22 @@ export class PXEService implements PXE {
|
|
|
652
735
|
* the function will also include the new contract's public functions in the transaction object.
|
|
653
736
|
*
|
|
654
737
|
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
655
|
-
* @param
|
|
738
|
+
* @param proofCreator - The proof creator to use for proving the execution.
|
|
656
739
|
* @param msgSender - (Optional) The message sender to use for the simulation.
|
|
657
|
-
* @returns An object
|
|
740
|
+
* @returns An object that contains:
|
|
658
741
|
* A private transaction object containing the proof, public inputs, and encrypted logs.
|
|
659
742
|
* The return values of the private execution
|
|
660
743
|
*/
|
|
661
|
-
async #simulateAndProve(
|
|
744
|
+
async #simulateAndProve(
|
|
745
|
+
txExecutionRequest: TxExecutionRequest,
|
|
746
|
+
proofCreator: ProofCreator,
|
|
747
|
+
msgSender?: AztecAddress,
|
|
748
|
+
): Promise<SimulatedTx> {
|
|
662
749
|
// Get values that allow us to reconstruct the block hash
|
|
663
750
|
const executionResult = await this.#simulate(txExecutionRequest, msgSender);
|
|
664
751
|
|
|
665
752
|
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
|
|
666
|
-
const kernelProver = new KernelProver(kernelOracle,
|
|
753
|
+
const kernelProver = new KernelProver(kernelOracle, proofCreator);
|
|
667
754
|
this.log.debug(`Executing kernel prover...`);
|
|
668
755
|
const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult);
|
|
669
756
|
|
|
@@ -746,4 +833,45 @@ export class PXEService implements PXE {
|
|
|
746
833
|
public async isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
|
|
747
834
|
return !!(await this.node.getContract(address));
|
|
748
835
|
}
|
|
836
|
+
|
|
837
|
+
public async getEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]> {
|
|
838
|
+
const blocks = await this.node.getBlocks(from, limit);
|
|
839
|
+
|
|
840
|
+
const txEffects = blocks.flatMap(block => block.body.txEffects);
|
|
841
|
+
const encryptedTxLogs = txEffects.flatMap(txEffect => txEffect.encryptedLogs);
|
|
842
|
+
|
|
843
|
+
const encryptedLogs = encryptedTxLogs.flatMap(encryptedTxLog => encryptedTxLog.unrollLogs());
|
|
844
|
+
|
|
845
|
+
const ivsk = await this.keyStore.getMasterSecretKey(ivpk);
|
|
846
|
+
|
|
847
|
+
const visibleEvents = encryptedLogs
|
|
848
|
+
.map(encryptedLog => TaggedLog.decryptAsIncoming(encryptedLog, ivsk, L1EventPayload))
|
|
849
|
+
.filter(item => item !== undefined) as TaggedLog<L1EventPayload>[];
|
|
850
|
+
|
|
851
|
+
const decodedEvents = visibleEvents
|
|
852
|
+
.map(visibleEvent => {
|
|
853
|
+
if (visibleEvent.payload === undefined) {
|
|
854
|
+
return undefined;
|
|
855
|
+
}
|
|
856
|
+
if (!visibleEvent.payload.eventTypeId.equals(eventMetadata.eventSelector)) {
|
|
857
|
+
return undefined;
|
|
858
|
+
}
|
|
859
|
+
if (visibleEvent.payload.event.items.length !== eventMetadata.fieldNames.length) {
|
|
860
|
+
throw new Error(
|
|
861
|
+
'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length',
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return eventMetadata.fieldNames.reduce(
|
|
866
|
+
(acc, curr, i) => ({
|
|
867
|
+
...acc,
|
|
868
|
+
[curr]: visibleEvent.payload.event.items[i],
|
|
869
|
+
}),
|
|
870
|
+
{} as T,
|
|
871
|
+
);
|
|
872
|
+
})
|
|
873
|
+
.filter(visibleEvent => visibleEvent !== undefined) as T[];
|
|
874
|
+
|
|
875
|
+
return decodedEvents;
|
|
876
|
+
}
|
|
749
877
|
}
|
|
@@ -78,7 +78,7 @@ export class SimulatorOracle implements DBOracle {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) {
|
|
81
|
-
const noteDaos = await this.db.
|
|
81
|
+
const noteDaos = await this.db.getIncomingNotes({
|
|
82
82
|
contractAddress,
|
|
83
83
|
storageSlot,
|
|
84
84
|
status,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AztecNode, type L2Block,
|
|
1
|
+
import { type AztecNode, type L2Block, MerkleTreeId, type TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { type NoteProcessorCaughtUpStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { type AztecAddress, type Fr, INITIAL_L2_BLOCK_NUM, type PublicKey } from '@aztec/circuits.js';
|
|
4
4
|
import { type SerialQueue } from '@aztec/foundation/fifo';
|
|
@@ -7,8 +7,9 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
7
7
|
import { type KeyStore } from '@aztec/key-store';
|
|
8
8
|
|
|
9
9
|
import { type DeferredNoteDao } from '../database/deferred_note_dao.js';
|
|
10
|
+
import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
10
11
|
import { type PxeDatabase } from '../database/index.js';
|
|
11
|
-
import { type
|
|
12
|
+
import { type OutgoingNoteDao } from '../database/outgoing_note_dao.js';
|
|
12
13
|
import { NoteProcessor } from '../note_processor/index.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -99,19 +100,13 @@ export class Synchronizer {
|
|
|
99
100
|
return false;
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
const noteEncryptedLogs = blocks.flatMap(block => block.body.noteEncryptedLogs);
|
|
103
|
-
|
|
104
103
|
// Update latest tree roots from the most recent block
|
|
105
104
|
const latestBlock = blocks[blocks.length - 1];
|
|
106
105
|
await this.setHeaderFromBlock(latestBlock);
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
this.log.debug(
|
|
110
|
-
`Forwarding ${logCount} encrypted logs and blocks to ${this.noteProcessors.length} note processors`,
|
|
111
|
-
);
|
|
107
|
+
this.log.debug(`Forwarding ${blocks.length} blocks to ${this.noteProcessors.length} note processors`);
|
|
112
108
|
for (const noteProcessor of this.noteProcessors) {
|
|
113
|
-
|
|
114
|
-
await noteProcessor.process(blocks, noteEncryptedLogs);
|
|
109
|
+
await noteProcessor.process(blocks);
|
|
115
110
|
}
|
|
116
111
|
return true;
|
|
117
112
|
} catch (err) {
|
|
@@ -177,11 +172,6 @@ export class Synchronizer {
|
|
|
177
172
|
throw new Error('No blocks in processor catch up mode');
|
|
178
173
|
}
|
|
179
174
|
|
|
180
|
-
const noteEncryptedLogs = blocks.flatMap(block => block.body.noteEncryptedLogs);
|
|
181
|
-
|
|
182
|
-
const logCount = L2BlockL2Logs.getTotalLogCount(noteEncryptedLogs);
|
|
183
|
-
this.log.debug(`Forwarding ${logCount} encrypted logs and blocks to note processors in catch up mode`);
|
|
184
|
-
|
|
185
175
|
for (const noteProcessor of catchUpGroup) {
|
|
186
176
|
// find the index of the first block that the note processor is not yet synced to
|
|
187
177
|
const index = blocks.findIndex(block => block.number > noteProcessor.status.syncedToBlock);
|
|
@@ -193,27 +183,24 @@ export class Synchronizer {
|
|
|
193
183
|
}
|
|
194
184
|
|
|
195
185
|
this.log.debug(
|
|
196
|
-
`Catching up note processor ${noteProcessor.
|
|
186
|
+
`Catching up note processor ${noteProcessor.account.toString()} by processing ${
|
|
197
187
|
blocks.length - index
|
|
198
188
|
} blocks`,
|
|
199
189
|
);
|
|
200
|
-
await noteProcessor.process(blocks.slice(index)
|
|
190
|
+
await noteProcessor.process(blocks.slice(index));
|
|
201
191
|
|
|
202
192
|
if (noteProcessor.status.syncedToBlock === toBlockNumber) {
|
|
203
193
|
// Note processor caught up, move it to `noteProcessors` from `noteProcessorsToCatchUp`.
|
|
204
|
-
this.log.debug(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
...noteProcessor.stats,
|
|
212
|
-
} satisfies NoteProcessorCaughtUpStats,
|
|
213
|
-
);
|
|
194
|
+
this.log.debug(`Note processor for ${noteProcessor.account.toString()} has caught up`, {
|
|
195
|
+
eventName: 'note-processor-caught-up',
|
|
196
|
+
account: noteProcessor.account.toString(),
|
|
197
|
+
duration: noteProcessor.timer.ms(),
|
|
198
|
+
dbSize: await this.db.estimateSize(),
|
|
199
|
+
...noteProcessor.stats,
|
|
200
|
+
} satisfies NoteProcessorCaughtUpStats);
|
|
214
201
|
|
|
215
202
|
this.noteProcessorsToCatchUp = this.noteProcessorsToCatchUp.filter(
|
|
216
|
-
np => !np.
|
|
203
|
+
np => !np.account.equals(noteProcessor.account),
|
|
217
204
|
);
|
|
218
205
|
this.noteProcessors.push(noteProcessor);
|
|
219
206
|
}
|
|
@@ -257,14 +244,14 @@ export class Synchronizer {
|
|
|
257
244
|
* @param startingBlock - The block where to start scanning for notes for this accounts.
|
|
258
245
|
* @returns A promise that resolves once the account is added to the Synchronizer.
|
|
259
246
|
*/
|
|
260
|
-
public addAccount(
|
|
261
|
-
const predicate = (x: NoteProcessor) => x.
|
|
247
|
+
public async addAccount(account: AztecAddress, keyStore: KeyStore, startingBlock: number) {
|
|
248
|
+
const predicate = (x: NoteProcessor) => x.account.equals(account);
|
|
262
249
|
const processor = this.noteProcessors.find(predicate) ?? this.noteProcessorsToCatchUp.find(predicate);
|
|
263
250
|
if (processor) {
|
|
264
251
|
return;
|
|
265
252
|
}
|
|
266
253
|
|
|
267
|
-
this.noteProcessorsToCatchUp.push(
|
|
254
|
+
this.noteProcessorsToCatchUp.push(await NoteProcessor.create(account, keyStore, this.db, this.node, startingBlock));
|
|
268
255
|
}
|
|
269
256
|
|
|
270
257
|
/**
|
|
@@ -280,9 +267,9 @@ export class Synchronizer {
|
|
|
280
267
|
if (!completeAddress) {
|
|
281
268
|
throw new Error(`Checking if account is synched is not possible for ${account} because it is not registered.`);
|
|
282
269
|
}
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
270
|
+
const findByAccountAddress = (x: NoteProcessor) => x.account.equals(completeAddress.address);
|
|
271
|
+
const processor =
|
|
272
|
+
this.noteProcessors.find(findByAccountAddress) ?? this.noteProcessorsToCatchUp.find(findByAccountAddress);
|
|
286
273
|
if (!processor) {
|
|
287
274
|
throw new Error(
|
|
288
275
|
`Checking if account is synched is not possible for ${account} because it is only registered as a recipient.`,
|
|
@@ -314,9 +301,7 @@ export class Synchronizer {
|
|
|
314
301
|
const lastBlockNumber = this.getSynchedBlockNumber();
|
|
315
302
|
return {
|
|
316
303
|
blocks: lastBlockNumber,
|
|
317
|
-
notes: Object.fromEntries(
|
|
318
|
-
this.noteProcessors.map(n => [n.masterIncomingViewingPublicKey.toString(), n.status.syncedToBlock]),
|
|
319
|
-
),
|
|
304
|
+
notes: Object.fromEntries(this.noteProcessors.map(n => [n.account.toString(), n.status.syncedToBlock])),
|
|
320
305
|
};
|
|
321
306
|
}
|
|
322
307
|
|
|
@@ -325,7 +310,7 @@ export class Synchronizer {
|
|
|
325
310
|
* @returns The note processor stats for notes for each public key being tracked.
|
|
326
311
|
*/
|
|
327
312
|
public getSyncStats() {
|
|
328
|
-
return Object.fromEntries(this.noteProcessors.map(n => [n.
|
|
313
|
+
return Object.fromEntries(this.noteProcessors.map(n => [n.account.toString(), n.stats]));
|
|
329
314
|
}
|
|
330
315
|
|
|
331
316
|
/**
|
|
@@ -348,40 +333,51 @@ export class Synchronizer {
|
|
|
348
333
|
}
|
|
349
334
|
|
|
350
335
|
// keep track of decoded notes
|
|
351
|
-
const
|
|
336
|
+
const incomingNotes: IncomingNoteDao[] = [];
|
|
337
|
+
const outgoingNotes: OutgoingNoteDao[] = [];
|
|
338
|
+
|
|
352
339
|
// now process each txHash
|
|
353
340
|
for (const deferredNotes of txHashToDeferredNotes.values()) {
|
|
354
341
|
// to be safe, try each note processor in case the deferred notes are for different accounts.
|
|
355
342
|
for (const processor of this.noteProcessors) {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
);
|
|
359
|
-
newNotes.push(...decodedNotes);
|
|
343
|
+
const { incomingNotes: inNotes, outgoingNotes: outNotes } = await processor.decodeDeferredNotes(deferredNotes);
|
|
344
|
+
incomingNotes.push(...inNotes);
|
|
345
|
+
outgoingNotes.push(...outNotes);
|
|
360
346
|
}
|
|
361
347
|
}
|
|
362
348
|
|
|
363
349
|
// now drop the deferred notes, and add the decoded notes
|
|
364
350
|
await this.db.removeDeferredNotesByContract(contractAddress);
|
|
365
|
-
await this.db.addNotes(
|
|
351
|
+
await this.db.addNotes(incomingNotes, outgoingNotes);
|
|
366
352
|
|
|
367
|
-
|
|
353
|
+
incomingNotes.forEach(noteDao => {
|
|
368
354
|
this.log.debug(
|
|
369
|
-
`Decoded deferred note for contract ${noteDao.contractAddress} at slot ${
|
|
355
|
+
`Decoded deferred incoming note for contract ${noteDao.contractAddress} at slot ${
|
|
370
356
|
noteDao.storageSlot
|
|
371
357
|
} with nullifier ${noteDao.siloedNullifier.toString()}`,
|
|
372
358
|
);
|
|
373
359
|
});
|
|
374
360
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
361
|
+
outgoingNotes.forEach(noteDao => {
|
|
362
|
+
this.log.debug(
|
|
363
|
+
`Decoded deferred outgoing note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`,
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
await this.#removeNullifiedNotes(incomingNotes);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async #removeNullifiedNotes(notes: IncomingNoteDao[]) {
|
|
371
|
+
// now group the decoded incoming notes by public key
|
|
372
|
+
const publicKeyToIncomingNotes: Map<PublicKey, IncomingNoteDao[]> = new Map();
|
|
373
|
+
for (const noteDao of notes) {
|
|
374
|
+
const notesForPublicKey = publicKeyToIncomingNotes.get(noteDao.ivpkM) ?? [];
|
|
379
375
|
notesForPublicKey.push(noteDao);
|
|
380
|
-
|
|
376
|
+
publicKeyToIncomingNotes.set(noteDao.ivpkM, notesForPublicKey);
|
|
381
377
|
}
|
|
382
378
|
|
|
383
379
|
// now for each group, look for the nullifiers in the nullifier tree
|
|
384
|
-
for (const [publicKey, notes] of
|
|
380
|
+
for (const [publicKey, notes] of publicKeyToIncomingNotes.entries()) {
|
|
385
381
|
const nullifiers = notes.map(n => n.siloedNullifier);
|
|
386
382
|
const relevantNullifiers: Fr[] = [];
|
|
387
383
|
for (const nullifier of nullifiers) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"note_dao.d.ts","sourceRoot":"","sources":["../../src/database/note_dao.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,EAAE,EAAS,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;GAEG;AACH,qBAAa,OAAQ,YAAW,QAAQ;IAEpC,kDAAkD;IAC3C,IAAI,EAAE,IAAI;IACjB,oDAAoD;IAC7C,eAAe,EAAE,YAAY;IACpC,iEAAiE;IAC1D,WAAW,EAAE,EAAE;IACtB,iDAAiD;IAC1C,UAAU,EAAE,EAAE;IACrB,kDAAkD;IAC3C,MAAM,EAAE,MAAM;IACrB,6BAA6B;IACtB,KAAK,EAAE,EAAE;IAChB;;;OAGG;IACI,aAAa,EAAE,EAAE;IACxB,8DAA8D;IACvD,eAAe,EAAE,EAAE;IAC1B,+DAA+D;IACxD,KAAK,EAAE,MAAM;IACpB,wDAAwD;IACjD,SAAS,EAAE,SAAS;;IAtB3B,kDAAkD;IAC3C,IAAI,EAAE,IAAI;IACjB,oDAAoD;IAC7C,eAAe,EAAE,YAAY;IACpC,iEAAiE;IAC1D,WAAW,EAAE,EAAE;IACtB,iDAAiD;IAC1C,UAAU,EAAE,EAAE;IACrB,kDAAkD;IAC3C,MAAM,EAAE,MAAM;IACrB,6BAA6B;IACtB,KAAK,EAAE,EAAE;IAChB;;;OAGG;IACI,aAAa,EAAE,EAAE;IACxB,8DAA8D;IACvD,eAAe,EAAE,EAAE;IAC1B,+DAA+D;IACxD,KAAK,EAAE,MAAM;IACpB,wDAAwD;IACjD,SAAS,EAAE,SAAS;IAG7B,QAAQ,IAAI,MAAM;IAclB,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY;IA4B/C,QAAQ;IAIR,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM;IAK7B;;;OAGG;IACI,OAAO;CAKf"}
|