@aztec/pxe 0.41.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.
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +5 -2
- package/dest/contract_data_oracle/index.d.ts +1 -0
- package/dest/contract_data_oracle/index.d.ts.map +1 -1
- package/dest/contract_data_oracle/index.js +7 -1
- package/dest/contract_data_oracle/private_functions_tree.d.ts.map +1 -1
- package/dest/contract_data_oracle/private_functions_tree.js +2 -2
- package/dest/database/deferred_note_dao.d.ts +2 -2
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +2 -2
- package/dest/database/incoming_note_dao.d.ts +73 -0
- package/dest/database/incoming_note_dao.d.ts.map +1 -0
- package/dest/database/incoming_note_dao.js +92 -0
- 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} +7 -12
- package/dest/database/outgoing_note_dao.d.ts.map +1 -0
- package/dest/database/outgoing_note_dao.js +83 -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/kernel_oracle/index.d.ts +4 -4
- package/dest/kernel_oracle/index.d.ts.map +1 -1
- package/dest/kernel_oracle/index.js +6 -17
- package/dest/kernel_prover/kernel_prover.d.ts +3 -0
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +44 -8
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts +2 -1
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts.map +1 -1
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.js +32 -12
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts +1 -1
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts.map +1 -1
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.js +9 -7
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.d.ts.map +1 -1
- package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.js +7 -3
- package/dest/kernel_prover/proving_data_oracle.d.ts +6 -6
- package/dest/kernel_prover/proving_data_oracle.d.ts.map +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 +123 -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.js +3 -3
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +4 -2
- package/dest/pxe_service/pxe_service.d.ts +14 -6
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +139 -87
- package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
- package/dest/pxe_service/test/pxe_test_suite.js +3 -16
- package/dest/simulator_oracle/index.d.ts +1 -0
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +5 -2
- package/dest/synchronizer/synchronizer.d.ts +9 -2
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +43 -34
- package/package.json +14 -14
- package/src/config/index.ts +11 -1
- package/src/contract_data_oracle/index.ts +7 -0
- package/src/contract_data_oracle/private_functions_tree.ts +3 -1
- package/src/database/deferred_note_dao.ts +1 -1
- package/src/database/{note_dao.ts → incoming_note_dao.ts} +10 -7
- package/src/database/kv_pxe_database.ts +127 -29
- package/src/database/outgoing_note_dao.ts +90 -0
- package/src/database/pxe_database.ts +23 -9
- package/src/database/pxe_database_test_suite.ts +93 -29
- package/src/kernel_oracle/index.ts +4 -17
- package/src/kernel_prover/kernel_prover.ts +76 -16
- package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts +79 -8
- package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.ts +9 -5
- package/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts +13 -1
- package/src/kernel_prover/proving_data_oracle.ts +5 -6
- package/src/note_processor/note_processor.ts +191 -121
- package/src/note_processor/produce_note_dao.ts +164 -50
- package/src/pxe_http/pxe_http_server.ts +2 -2
- package/src/pxe_service/create_pxe_service.ts +3 -1
- package/src/pxe_service/pxe_service.ts +210 -149
- package/src/pxe_service/test/pxe_test_suite.ts +0 -20
- package/src/simulator_oracle/index.ts +5 -1
- package/src/synchronizer/synchronizer.ts +55 -50
- package/dest/database/note_dao.d.ts.map +0 -1
- package/dest/database/note_dao.js +0 -89
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AuthWitness,
|
|
3
3
|
type AztecNode,
|
|
4
|
+
EncryptedNoteTxL2Logs,
|
|
4
5
|
EncryptedTxL2Logs,
|
|
6
|
+
type EventMetadata,
|
|
5
7
|
ExtendedNote,
|
|
6
8
|
type FunctionCall,
|
|
7
9
|
type GetUnencryptedLogsResponse,
|
|
10
|
+
type IncomingNotesFilter,
|
|
11
|
+
L1EventPayload,
|
|
8
12
|
type L2Block,
|
|
9
13
|
type LogFilter,
|
|
10
14
|
MerkleTreeId,
|
|
11
|
-
type
|
|
15
|
+
type OutgoingNotesFilter,
|
|
12
16
|
type PXE,
|
|
17
|
+
type PXEInfo,
|
|
13
18
|
type ProofCreator,
|
|
14
19
|
SimulatedTx,
|
|
15
20
|
SimulationError,
|
|
21
|
+
TaggedLog,
|
|
16
22
|
Tx,
|
|
17
23
|
type TxEffect,
|
|
18
24
|
type TxExecutionRequest,
|
|
@@ -21,27 +27,24 @@ import {
|
|
|
21
27
|
UnencryptedTxL2Logs,
|
|
22
28
|
isNoirCallStackUnresolved,
|
|
23
29
|
} from '@aztec/circuit-types';
|
|
24
|
-
import { type TxPXEProcessingStats } from '@aztec/circuit-types/stats';
|
|
25
30
|
import {
|
|
26
31
|
AztecAddress,
|
|
27
|
-
CallRequest,
|
|
28
32
|
type CompleteAddress,
|
|
29
|
-
FunctionData,
|
|
30
|
-
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
|
|
31
33
|
type PartialAddress,
|
|
32
|
-
type PrivateKernelTailCircuitPublicInputs,
|
|
33
|
-
type PublicCallRequest,
|
|
34
34
|
computeContractClassId,
|
|
35
35
|
getContractClassFromArtifact,
|
|
36
36
|
} from '@aztec/circuits.js';
|
|
37
37
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
38
38
|
import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
|
|
39
|
-
import {
|
|
40
|
-
import { type Fq, Fr } from '@aztec/foundation/fields';
|
|
39
|
+
import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
|
|
41
40
|
import { SerialQueue } from '@aztec/foundation/fifo';
|
|
42
41
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
43
|
-
import { Timer } from '@aztec/foundation/timer';
|
|
44
42
|
import { type KeyStore } from '@aztec/key-store';
|
|
43
|
+
import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
|
|
44
|
+
import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
|
|
45
|
+
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
|
|
46
|
+
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
|
|
47
|
+
import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint';
|
|
45
48
|
import {
|
|
46
49
|
type AcirSimulator,
|
|
47
50
|
type ExecutionResult,
|
|
@@ -58,10 +61,11 @@ import { type NodeInfo } from '@aztec/types/interfaces';
|
|
|
58
61
|
|
|
59
62
|
import { type PXEServiceConfig, getPackageInfo } from '../config/index.js';
|
|
60
63
|
import { ContractDataOracle } from '../contract_data_oracle/index.js';
|
|
64
|
+
import { IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
61
65
|
import { type PxeDatabase } from '../database/index.js';
|
|
62
|
-
import { NoteDao } from '../database/note_dao.js';
|
|
63
66
|
import { KernelOracle } from '../kernel_oracle/index.js';
|
|
64
67
|
import { KernelProver } from '../kernel_prover/kernel_prover.js';
|
|
68
|
+
import { TestProofCreator } from '../kernel_prover/test/test_circuit_prover.js';
|
|
65
69
|
import { getAcirSimulator } from '../simulator/index.js';
|
|
66
70
|
import { Synchronizer } from '../synchronizer/index.js';
|
|
67
71
|
|
|
@@ -73,11 +77,13 @@ export class PXEService implements PXE {
|
|
|
73
77
|
private contractDataOracle: ContractDataOracle;
|
|
74
78
|
private simulator: AcirSimulator;
|
|
75
79
|
private log: DebugLogger;
|
|
76
|
-
private
|
|
80
|
+
private packageVersion: string;
|
|
77
81
|
// serialize synchronizer and calls to proveTx.
|
|
78
82
|
// ensures that state is not changed while simulating
|
|
79
83
|
private jobQueue = new SerialQueue();
|
|
80
84
|
|
|
85
|
+
private fakeProofCreator = new TestProofCreator();
|
|
86
|
+
|
|
81
87
|
constructor(
|
|
82
88
|
private keyStore: KeyStore,
|
|
83
89
|
private node: AztecNode,
|
|
@@ -90,7 +96,7 @@ export class PXEService implements PXE {
|
|
|
90
96
|
this.synchronizer = new Synchronizer(node, db, this.jobQueue, logSuffix);
|
|
91
97
|
this.contractDataOracle = new ContractDataOracle(db);
|
|
92
98
|
this.simulator = getAcirSimulator(db, node, keyStore, this.contractDataOracle);
|
|
93
|
-
this.
|
|
99
|
+
this.packageVersion = getPackageInfo().version;
|
|
94
100
|
|
|
95
101
|
this.jobQueue.start();
|
|
96
102
|
}
|
|
@@ -122,11 +128,7 @@ export class PXEService implements PXE {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
count++;
|
|
125
|
-
this.synchronizer.addAccount(
|
|
126
|
-
address.publicKeys.masterIncomingViewingPublicKey,
|
|
127
|
-
this.keyStore,
|
|
128
|
-
this.config.l2StartingBlock,
|
|
129
|
-
);
|
|
131
|
+
await this.synchronizer.addAccount(address.address, this.keyStore, this.config.l2StartingBlock);
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
if (count > 0) {
|
|
@@ -178,6 +180,10 @@ export class PXEService implements PXE {
|
|
|
178
180
|
return artifact && getContractClassFromArtifact(artifact);
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
public getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
|
|
184
|
+
return this.db.getContractArtifact(id);
|
|
185
|
+
}
|
|
186
|
+
|
|
181
187
|
public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
|
|
182
188
|
const accounts = await this.keyStore.getAccounts();
|
|
183
189
|
const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress);
|
|
@@ -185,10 +191,7 @@ export class PXEService implements PXE {
|
|
|
185
191
|
this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
|
|
186
192
|
return accountCompleteAddress;
|
|
187
193
|
} else {
|
|
188
|
-
|
|
189
|
-
accountCompleteAddress.address,
|
|
190
|
-
);
|
|
191
|
-
this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock);
|
|
194
|
+
await this.synchronizer.addAccount(accountCompleteAddress.address, this.keyStore, this.config.l2StartingBlock);
|
|
192
195
|
this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
|
|
193
196
|
this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
|
|
194
197
|
}
|
|
@@ -259,6 +262,7 @@ export class PXEService implements PXE {
|
|
|
259
262
|
);
|
|
260
263
|
}
|
|
261
264
|
await this.db.addContractArtifact(contractClassId, artifact);
|
|
265
|
+
await this.node.addContractArtifact(instance.address, artifact);
|
|
262
266
|
} else {
|
|
263
267
|
// Otherwise, make sure there is an artifact already registered for that class id
|
|
264
268
|
artifact = await this.db.getContractArtifact(instance.contractClassId);
|
|
@@ -285,19 +289,40 @@ export class PXEService implements PXE {
|
|
|
285
289
|
return await this.node.getPublicStorageAt(contract, slot);
|
|
286
290
|
}
|
|
287
291
|
|
|
288
|
-
public async
|
|
289
|
-
const noteDaos = await this.db.
|
|
292
|
+
public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
|
|
293
|
+
const noteDaos = await this.db.getIncomingNotes(filter);
|
|
290
294
|
|
|
291
|
-
// TODO(
|
|
292
|
-
// 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
|
|
293
297
|
const extendedNotes = noteDaos.map(async dao => {
|
|
294
298
|
let owner = filter.owner;
|
|
295
299
|
if (owner === undefined) {
|
|
296
300
|
const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
|
|
297
|
-
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.
|
|
301
|
+
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.ivpkM),
|
|
298
302
|
);
|
|
299
303
|
if (completeAddresses === undefined) {
|
|
300
|
-
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()}`);
|
|
301
326
|
}
|
|
302
327
|
owner = completeAddresses.address;
|
|
303
328
|
}
|
|
@@ -318,13 +343,15 @@ export class PXEService implements PXE {
|
|
|
318
343
|
}
|
|
319
344
|
|
|
320
345
|
for (const nonce of nonces) {
|
|
321
|
-
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
+
);
|
|
328
355
|
|
|
329
356
|
const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
|
|
330
357
|
if (index === undefined) {
|
|
@@ -338,7 +365,7 @@ export class PXEService implements PXE {
|
|
|
338
365
|
}
|
|
339
366
|
|
|
340
367
|
await this.db.addNote(
|
|
341
|
-
new
|
|
368
|
+
new IncomingNoteDao(
|
|
342
369
|
note.note,
|
|
343
370
|
note.contractAddress,
|
|
344
371
|
note.storageSlot,
|
|
@@ -354,6 +381,54 @@ export class PXEService implements PXE {
|
|
|
354
381
|
}
|
|
355
382
|
}
|
|
356
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
|
+
|
|
357
432
|
/**
|
|
358
433
|
* Finds the nonce(s) for a given note.
|
|
359
434
|
* @param note - The note to find the nonces for.
|
|
@@ -373,11 +448,12 @@ export class PXEService implements PXE {
|
|
|
373
448
|
// Remove this once notes added from public also include nonces.
|
|
374
449
|
{
|
|
375
450
|
const publicNoteNonce = Fr.ZERO;
|
|
376
|
-
const { siloedNoteHash } = await this.simulator.
|
|
451
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
377
452
|
note.contractAddress,
|
|
378
453
|
publicNoteNonce,
|
|
379
454
|
note.storageSlot,
|
|
380
455
|
note.noteTypeId,
|
|
456
|
+
false,
|
|
381
457
|
note.note,
|
|
382
458
|
);
|
|
383
459
|
if (tx.noteHashes.some(hash => hash.equals(siloedNoteHash))) {
|
|
@@ -394,11 +470,12 @@ export class PXEService implements PXE {
|
|
|
394
470
|
}
|
|
395
471
|
|
|
396
472
|
const nonce = computeNoteHashNonce(firstNullifier, i);
|
|
397
|
-
const { siloedNoteHash } = await this.simulator.
|
|
473
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
398
474
|
note.contractAddress,
|
|
399
475
|
nonce,
|
|
400
476
|
note.storageSlot,
|
|
401
477
|
note.noteTypeId,
|
|
478
|
+
false,
|
|
402
479
|
note.note,
|
|
403
480
|
);
|
|
404
481
|
if (hash.equals(siloedNoteHash)) {
|
|
@@ -417,8 +494,14 @@ export class PXEService implements PXE {
|
|
|
417
494
|
return await this.node.getBlock(blockNumber);
|
|
418
495
|
}
|
|
419
496
|
|
|
420
|
-
public
|
|
421
|
-
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
|
+
});
|
|
422
505
|
}
|
|
423
506
|
|
|
424
507
|
public async simulateTx(
|
|
@@ -426,29 +509,16 @@ export class PXEService implements PXE {
|
|
|
426
509
|
simulatePublic: boolean,
|
|
427
510
|
msgSender: AztecAddress | undefined = undefined,
|
|
428
511
|
): Promise<SimulatedTx> {
|
|
429
|
-
if (!txRequest.functionData.isPrivate) {
|
|
430
|
-
throw new Error(`Public entrypoints are not allowed`);
|
|
431
|
-
}
|
|
432
512
|
return await this.jobQueue.put(async () => {
|
|
433
|
-
const
|
|
434
|
-
const simulatedTx = await this.#simulateAndProve(txRequest, msgSender);
|
|
435
|
-
// We log only if the msgSender is undefined, as simulating with a different msgSender
|
|
436
|
-
// is unlikely to be a real transaction, and likely to be only used to read data.
|
|
437
|
-
// Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
|
|
438
|
-
// If we log, the `getTxHash` function will throw.
|
|
439
|
-
|
|
440
|
-
if (!msgSender) {
|
|
441
|
-
this.log.debug(`Processed private part of ${simulatedTx.tx.getTxHash()}`, {
|
|
442
|
-
eventName: 'tx-pxe-processing',
|
|
443
|
-
duration: timer.ms(),
|
|
444
|
-
...simulatedTx.tx.getStats(),
|
|
445
|
-
} satisfies TxPXEProcessingStats);
|
|
446
|
-
}
|
|
447
|
-
|
|
513
|
+
const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
|
|
448
514
|
if (simulatePublic) {
|
|
449
515
|
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
|
|
450
516
|
}
|
|
451
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.
|
|
452
522
|
if (!msgSender) {
|
|
453
523
|
this.log.info(`Executed local simulation for ${simulatedTx.tx.getTxHash()}`);
|
|
454
524
|
}
|
|
@@ -518,29 +588,49 @@ export class PXEService implements PXE {
|
|
|
518
588
|
}
|
|
519
589
|
|
|
520
590
|
return {
|
|
591
|
+
name: functionDao.name,
|
|
521
592
|
args: encodeArguments(functionDao, args),
|
|
522
|
-
|
|
593
|
+
selector: FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
|
|
594
|
+
type: functionDao.functionType,
|
|
523
595
|
to,
|
|
524
596
|
isStatic: functionDao.isStatic,
|
|
597
|
+
returnTypes: functionDao.returnTypes,
|
|
525
598
|
};
|
|
526
599
|
}
|
|
527
600
|
|
|
528
601
|
public async getNodeInfo(): Promise<NodeInfo> {
|
|
529
|
-
const [
|
|
602
|
+
const [nodeVersion, protocolVersion, chainId, contractAddresses, protocolContractAddresses] = await Promise.all([
|
|
603
|
+
this.node.getNodeVersion(),
|
|
530
604
|
this.node.getVersion(),
|
|
531
605
|
this.node.getChainId(),
|
|
532
606
|
this.node.getL1ContractAddresses(),
|
|
607
|
+
this.node.getProtocolContractAddresses(),
|
|
533
608
|
]);
|
|
534
609
|
|
|
535
610
|
const nodeInfo: NodeInfo = {
|
|
536
|
-
nodeVersion
|
|
611
|
+
nodeVersion,
|
|
537
612
|
chainId,
|
|
538
|
-
protocolVersion
|
|
613
|
+
protocolVersion,
|
|
539
614
|
l1ContractAddresses: contractAddresses,
|
|
615
|
+
protocolContractAddresses: protocolContractAddresses,
|
|
540
616
|
};
|
|
617
|
+
|
|
541
618
|
return nodeInfo;
|
|
542
619
|
}
|
|
543
620
|
|
|
621
|
+
public getPXEInfo(): Promise<PXEInfo> {
|
|
622
|
+
return Promise.resolve({
|
|
623
|
+
pxeVersion: this.packageVersion,
|
|
624
|
+
protocolContractAddresses: {
|
|
625
|
+
classRegisterer: ClassRegistererAddress,
|
|
626
|
+
gasToken: getCanonicalGasToken().address,
|
|
627
|
+
instanceDeployer: getCanonicalInstanceDeployer().address,
|
|
628
|
+
keyRegistry: getCanonicalKeyRegistryAddress(),
|
|
629
|
+
multiCallEntrypoint: getCanonicalMultiCallEntrypointAddress(),
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
544
634
|
/**
|
|
545
635
|
* Retrieves the simulation parameters required to run an ACIR simulation.
|
|
546
636
|
* This includes the contract address, function artifact, and historical tree roots.
|
|
@@ -550,14 +640,10 @@ export class PXEService implements PXE {
|
|
|
550
640
|
*/
|
|
551
641
|
async #getSimulationParameters(execRequest: FunctionCall | TxExecutionRequest) {
|
|
552
642
|
const contractAddress = (execRequest as FunctionCall).to ?? (execRequest as TxExecutionRequest).origin;
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
);
|
|
557
|
-
const debug = await this.contractDataOracle.getFunctionDebugMetadata(
|
|
558
|
-
contractAddress,
|
|
559
|
-
execRequest.functionData.selector,
|
|
560
|
-
);
|
|
643
|
+
const functionSelector =
|
|
644
|
+
(execRequest as FunctionCall).selector ?? (execRequest as TxExecutionRequest).functionSelector;
|
|
645
|
+
const functionArtifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, functionSelector);
|
|
646
|
+
const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, functionSelector);
|
|
561
647
|
|
|
562
648
|
return {
|
|
563
649
|
contractAddress,
|
|
@@ -649,31 +735,31 @@ export class PXEService implements PXE {
|
|
|
649
735
|
* the function will also include the new contract's public functions in the transaction object.
|
|
650
736
|
*
|
|
651
737
|
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
652
|
-
* @param
|
|
738
|
+
* @param proofCreator - The proof creator to use for proving the execution.
|
|
653
739
|
* @param msgSender - (Optional) The message sender to use for the simulation.
|
|
654
|
-
* @returns An object
|
|
740
|
+
* @returns An object that contains:
|
|
655
741
|
* A private transaction object containing the proof, public inputs, and encrypted logs.
|
|
656
742
|
* The return values of the private execution
|
|
657
743
|
*/
|
|
658
|
-
async #simulateAndProve(
|
|
744
|
+
async #simulateAndProve(
|
|
745
|
+
txExecutionRequest: TxExecutionRequest,
|
|
746
|
+
proofCreator: ProofCreator,
|
|
747
|
+
msgSender?: AztecAddress,
|
|
748
|
+
): Promise<SimulatedTx> {
|
|
659
749
|
// Get values that allow us to reconstruct the block hash
|
|
660
750
|
const executionResult = await this.#simulate(txExecutionRequest, msgSender);
|
|
661
751
|
|
|
662
752
|
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
|
|
663
|
-
const kernelProver = new KernelProver(kernelOracle,
|
|
753
|
+
const kernelProver = new KernelProver(kernelOracle, proofCreator);
|
|
664
754
|
this.log.debug(`Executing kernel prover...`);
|
|
665
755
|
const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult);
|
|
666
756
|
|
|
667
|
-
const noteEncryptedLogs = new
|
|
757
|
+
const noteEncryptedLogs = new EncryptedNoteTxL2Logs([collectSortedNoteEncryptedLogs(executionResult)]);
|
|
668
758
|
const unencryptedLogs = new UnencryptedTxL2Logs([collectSortedUnencryptedLogs(executionResult)]);
|
|
669
759
|
const encryptedLogs = new EncryptedTxL2Logs([collectSortedEncryptedLogs(executionResult)]);
|
|
670
760
|
const enqueuedPublicFunctions = collectEnqueuedPublicFunctionCalls(executionResult);
|
|
671
761
|
const teardownPublicFunction = collectPublicTeardownFunctionCall(executionResult);
|
|
672
762
|
|
|
673
|
-
// HACK(#1639): Manually patches the ordering of the public call stack
|
|
674
|
-
// TODO(#757): Enforce proper ordering of enqueued public calls
|
|
675
|
-
await this.patchPublicCallStackOrdering(publicInputs, enqueuedPublicFunctions);
|
|
676
|
-
|
|
677
763
|
const tx = new Tx(
|
|
678
764
|
publicInputs,
|
|
679
765
|
proof.binaryProof,
|
|
@@ -724,76 +810,6 @@ export class PXEService implements PXE {
|
|
|
724
810
|
);
|
|
725
811
|
}
|
|
726
812
|
|
|
727
|
-
// HACK(#1639): this is a hack to fix ordering of public calls enqueued in the call stack. Since the private kernel
|
|
728
|
-
// cannot keep track of side effects that happen after or before a nested call, we override the public call stack
|
|
729
|
-
// it emits with whatever we got from the simulator collected enqueued calls. As a sanity check, we at least verify
|
|
730
|
-
// that the elements are the same, so we are only tweaking their ordering.
|
|
731
|
-
// See yarn-project/end-to-end/src/e2e_ordering.test.ts
|
|
732
|
-
// See https://github.com/AztecProtocol/aztec-packages/issues/1615
|
|
733
|
-
// TODO(#757): Enforce proper ordering of enqueued public calls
|
|
734
|
-
private async patchPublicCallStackOrdering(
|
|
735
|
-
publicInputs: PrivateKernelTailCircuitPublicInputs,
|
|
736
|
-
enqueuedPublicCalls: PublicCallRequest[],
|
|
737
|
-
) {
|
|
738
|
-
if (!publicInputs.forPublic) {
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
const enqueuedPublicCallStackItems = await Promise.all(enqueuedPublicCalls.map(c => c.toCallRequest()));
|
|
743
|
-
|
|
744
|
-
// Validate all items in enqueued public calls are in the kernel emitted stack
|
|
745
|
-
const enqueuedRevertiblePublicCallStackItems = enqueuedPublicCallStackItems.filter(enqueued =>
|
|
746
|
-
publicInputs.forPublic!.end.publicCallStack.find(item => item.equals(enqueued)),
|
|
747
|
-
);
|
|
748
|
-
|
|
749
|
-
const revertibleStackSize = arrayNonEmptyLength(publicInputs.forPublic.end.publicCallStack, item => item.isEmpty());
|
|
750
|
-
|
|
751
|
-
if (enqueuedRevertiblePublicCallStackItems.length !== revertibleStackSize) {
|
|
752
|
-
throw new Error(
|
|
753
|
-
`Enqueued revertible public function calls and revertible public call stack do not match.\nEnqueued calls: ${enqueuedRevertiblePublicCallStackItems
|
|
754
|
-
.map(h => h.hash.toString())
|
|
755
|
-
.join(', ')}\nPublic call stack: ${publicInputs.forPublic.end.publicCallStack
|
|
756
|
-
.map(i => i.toString())
|
|
757
|
-
.join(', ')}`,
|
|
758
|
-
);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
// Override kernel output
|
|
762
|
-
publicInputs.forPublic.end.publicCallStack = padArrayEnd(
|
|
763
|
-
enqueuedRevertiblePublicCallStackItems,
|
|
764
|
-
CallRequest.empty(),
|
|
765
|
-
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
|
|
766
|
-
);
|
|
767
|
-
|
|
768
|
-
// Do the same for non-revertible
|
|
769
|
-
|
|
770
|
-
const enqueuedNonRevertiblePublicCallStackItems = enqueuedPublicCallStackItems.filter(enqueued =>
|
|
771
|
-
publicInputs.forPublic!.endNonRevertibleData.publicCallStack.find(item => item.equals(enqueued)),
|
|
772
|
-
);
|
|
773
|
-
|
|
774
|
-
const nonRevertibleStackSize = arrayNonEmptyLength(
|
|
775
|
-
publicInputs.forPublic.endNonRevertibleData.publicCallStack,
|
|
776
|
-
item => item.isEmpty(),
|
|
777
|
-
);
|
|
778
|
-
|
|
779
|
-
if (enqueuedNonRevertiblePublicCallStackItems.length !== nonRevertibleStackSize) {
|
|
780
|
-
throw new Error(
|
|
781
|
-
`Enqueued non-revertible public function calls and non-revertible public call stack do not match.\nEnqueued calls: ${enqueuedNonRevertiblePublicCallStackItems
|
|
782
|
-
.map(h => h.hash.toString())
|
|
783
|
-
.join(', ')}\nPublic call stack: ${publicInputs.forPublic.endNonRevertibleData.publicCallStack
|
|
784
|
-
.map(i => i.toString())
|
|
785
|
-
.join(', ')}`,
|
|
786
|
-
);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// Override kernel output
|
|
790
|
-
publicInputs.forPublic.endNonRevertibleData.publicCallStack = padArrayEnd(
|
|
791
|
-
enqueuedNonRevertiblePublicCallStackItems,
|
|
792
|
-
CallRequest.empty(),
|
|
793
|
-
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
|
|
794
|
-
);
|
|
795
|
-
}
|
|
796
|
-
|
|
797
813
|
public async isGlobalStateSynchronized() {
|
|
798
814
|
return await this.synchronizer.isGlobalStateSynchronized();
|
|
799
815
|
}
|
|
@@ -806,6 +822,10 @@ export class PXEService implements PXE {
|
|
|
806
822
|
return Promise.resolve(this.synchronizer.getSyncStatus());
|
|
807
823
|
}
|
|
808
824
|
|
|
825
|
+
public getSyncStats() {
|
|
826
|
+
return Promise.resolve(this.synchronizer.getSyncStats());
|
|
827
|
+
}
|
|
828
|
+
|
|
809
829
|
public async isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
|
|
810
830
|
return !!(await this.node.getContractClass(id));
|
|
811
831
|
}
|
|
@@ -813,4 +833,45 @@ export class PXEService implements PXE {
|
|
|
813
833
|
public async isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
|
|
814
834
|
return !!(await this.node.getContract(address));
|
|
815
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 (!FunctionSelector.fromField(visibleEvent.payload.eventTypeId).equals(eventMetadata.functionSelector)) {
|
|
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
|
+
}
|
|
816
877
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type PXE,
|
|
3
|
-
TxExecutionRequest,
|
|
4
3
|
randomContractArtifact,
|
|
5
4
|
randomContractInstanceWithAddress,
|
|
6
5
|
randomDeployedContract,
|
|
@@ -9,11 +8,9 @@ import {
|
|
|
9
8
|
AztecAddress,
|
|
10
9
|
CompleteAddress,
|
|
11
10
|
Fr,
|
|
12
|
-
FunctionData,
|
|
13
11
|
INITIAL_L2_BLOCK_NUM,
|
|
14
12
|
Point,
|
|
15
13
|
PublicKeys,
|
|
16
|
-
TxContext,
|
|
17
14
|
getContractClassFromArtifact,
|
|
18
15
|
} from '@aztec/circuits.js';
|
|
19
16
|
|
|
@@ -126,23 +123,6 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise<PXE>) =>
|
|
|
126
123
|
await expect(pxe.registerContract({ instance, artifact })).rejects.toThrow(/Artifact does not match/i);
|
|
127
124
|
});
|
|
128
125
|
|
|
129
|
-
it('throws when simulating a tx targeting public entrypoint', async () => {
|
|
130
|
-
const functionData = FunctionData.empty();
|
|
131
|
-
functionData.isPrivate = false;
|
|
132
|
-
const txExecutionRequest = TxExecutionRequest.from({
|
|
133
|
-
origin: AztecAddress.random(),
|
|
134
|
-
firstCallArgsHash: new Fr(0),
|
|
135
|
-
functionData,
|
|
136
|
-
txContext: TxContext.empty(),
|
|
137
|
-
argsOfCalls: [],
|
|
138
|
-
authWitnesses: [],
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
await expect(async () => await pxe.proveTx(txExecutionRequest, false)).rejects.toThrow(
|
|
142
|
-
'Public entrypoints are not allowed',
|
|
143
|
-
);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
126
|
// Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `simulateUnconstrained` here as it requires
|
|
147
127
|
// a larger setup and it's sufficiently tested in the e2e tests.
|
|
148
128
|
|
|
@@ -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,
|
|
@@ -230,4 +230,8 @@ export class SimulatorOracle implements DBOracle {
|
|
|
230
230
|
public async getBlockNumber(): Promise<number> {
|
|
231
231
|
return await this.aztecNode.getBlockNumber();
|
|
232
232
|
}
|
|
233
|
+
|
|
234
|
+
public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string> {
|
|
235
|
+
return this.contractDataOracle.getDebugFunctionName(contractAddress, selector);
|
|
236
|
+
}
|
|
233
237
|
}
|