@aztec/txe 0.66.0 → 0.67.1
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/bin/index.js +3 -3
- package/dest/node/txe_node.d.ts +349 -0
- package/dest/node/txe_node.d.ts.map +1 -0
- package/dest/node/txe_node.js +521 -0
- package/dest/oracle/txe_oracle.d.ts +18 -6
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +135 -28
- package/dest/txe_service/txe_service.d.ts +4 -1
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +15 -6
- package/dest/util/txe_database.d.ts +3 -3
- package/dest/util/txe_database.d.ts.map +1 -1
- package/dest/util/txe_database.js +4 -3
- package/package.json +18 -14
- package/src/bin/index.ts +2 -2
- package/src/node/txe_node.ts +666 -0
- package/src/oracle/txe_oracle.ts +187 -32
- package/src/txe_service/txe_service.ts +18 -5
- package/src/util/txe_database.ts +6 -5
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -7,17 +7,20 @@ import {
|
|
|
7
7
|
PublicDataWitness,
|
|
8
8
|
PublicExecutionRequest,
|
|
9
9
|
SimulationError,
|
|
10
|
+
TxEffect,
|
|
11
|
+
TxHash,
|
|
10
12
|
type UnencryptedL2Log,
|
|
11
13
|
} from '@aztec/circuit-types';
|
|
12
14
|
import { type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
|
|
13
15
|
import {
|
|
16
|
+
BlockHeader,
|
|
14
17
|
CallContext,
|
|
15
18
|
type ContractInstance,
|
|
16
19
|
type ContractInstanceWithAddress,
|
|
20
|
+
DEPLOYER_CONTRACT_ADDRESS,
|
|
17
21
|
Gas,
|
|
18
22
|
GasFees,
|
|
19
23
|
GlobalVariables,
|
|
20
|
-
Header,
|
|
21
24
|
IndexedTaggingSecret,
|
|
22
25
|
type KeyValidationRequest,
|
|
23
26
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
@@ -28,6 +31,7 @@ import {
|
|
|
28
31
|
type PUBLIC_DATA_TREE_HEIGHT,
|
|
29
32
|
PUBLIC_DISPATCH_SELECTOR,
|
|
30
33
|
PrivateContextInputs,
|
|
34
|
+
type PrivateLog,
|
|
31
35
|
PublicDataTreeLeaf,
|
|
32
36
|
type PublicDataTreeLeafPreimage,
|
|
33
37
|
type PublicDataWrite,
|
|
@@ -37,7 +41,13 @@ import {
|
|
|
37
41
|
getContractClassFromArtifact,
|
|
38
42
|
} from '@aztec/circuits.js';
|
|
39
43
|
import { Schnorr } from '@aztec/circuits.js/barretenberg';
|
|
40
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
computeNoteHashNonce,
|
|
46
|
+
computePublicDataTreeLeafSlot,
|
|
47
|
+
computeUniqueNoteHash,
|
|
48
|
+
siloNoteHash,
|
|
49
|
+
siloNullifier,
|
|
50
|
+
} from '@aztec/circuits.js/hash';
|
|
41
51
|
import {
|
|
42
52
|
type ContractArtifact,
|
|
43
53
|
type FunctionAbi,
|
|
@@ -51,10 +61,10 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
51
61
|
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
52
62
|
import { Timer } from '@aztec/foundation/timer';
|
|
53
63
|
import { type KeyStore } from '@aztec/key-store';
|
|
54
|
-
import { ContractDataOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
64
|
+
import { ContractDataOracle, SimulatorOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
55
65
|
import {
|
|
56
66
|
ExecutionError,
|
|
57
|
-
|
|
67
|
+
ExecutionNoteCache,
|
|
58
68
|
type MessageLoadOracleInputs,
|
|
59
69
|
type NoteData,
|
|
60
70
|
Oracle,
|
|
@@ -75,6 +85,7 @@ import { createTxForPublicCall } from '@aztec/simulator/public/fixtures';
|
|
|
75
85
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
76
86
|
import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
|
|
77
87
|
|
|
88
|
+
import { TXENode } from '../node/txe_node.js';
|
|
78
89
|
import { type TXEDatabase } from '../util/txe_database.js';
|
|
79
90
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
80
91
|
import { TXEWorldStateDB } from '../util/txe_world_state_db.js';
|
|
@@ -90,10 +101,20 @@ export class TXE implements TypedOracle {
|
|
|
90
101
|
private nestedCallReturndata: Fr[] = [];
|
|
91
102
|
|
|
92
103
|
private contractDataOracle: ContractDataOracle;
|
|
104
|
+
private simulatorOracle: SimulatorOracle;
|
|
93
105
|
|
|
94
106
|
private version: Fr = Fr.ONE;
|
|
95
107
|
private chainId: Fr = Fr.ONE;
|
|
96
108
|
|
|
109
|
+
private uniqueNoteHashesFromPublic: Fr[] = [];
|
|
110
|
+
private siloedNullifiersFromPublic: Fr[] = [];
|
|
111
|
+
private privateLogs: PrivateLog[] = [];
|
|
112
|
+
private publicLogs: UnencryptedL2Log[] = [];
|
|
113
|
+
|
|
114
|
+
private committedBlocks = new Set<number>();
|
|
115
|
+
|
|
116
|
+
private node = new TXENode(this.blockNumber);
|
|
117
|
+
|
|
97
118
|
constructor(
|
|
98
119
|
private logger: Logger,
|
|
99
120
|
private trees: MerkleTrees,
|
|
@@ -106,6 +127,7 @@ export class TXE implements TypedOracle {
|
|
|
106
127
|
this.contractAddress = AztecAddress.random();
|
|
107
128
|
// Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404)
|
|
108
129
|
this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE);
|
|
130
|
+
this.simulatorOracle = new SimulatorOracle(this.contractDataOracle, txeDatabase, keyStore, this.node);
|
|
109
131
|
}
|
|
110
132
|
|
|
111
133
|
// Utils
|
|
@@ -156,6 +178,7 @@ export class TXE implements TypedOracle {
|
|
|
156
178
|
|
|
157
179
|
setBlockNumber(blockNumber: number) {
|
|
158
180
|
this.blockNumber = blockNumber;
|
|
181
|
+
this.node.setBlockNumber(blockNumber);
|
|
159
182
|
}
|
|
160
183
|
|
|
161
184
|
getTrees() {
|
|
@@ -210,7 +233,7 @@ export class TXE implements TypedOracle {
|
|
|
210
233
|
}
|
|
211
234
|
|
|
212
235
|
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
213
|
-
const account = this.txeDatabase.getAccount(address);
|
|
236
|
+
const account = await this.txeDatabase.getAccount(address);
|
|
214
237
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
215
238
|
const schnorr = new Schnorr();
|
|
216
239
|
const signature = schnorr.constructSignature(messageHash.toBuffer(), privateKey).toBuffer();
|
|
@@ -236,18 +259,66 @@ export class TXE implements TypedOracle {
|
|
|
236
259
|
);
|
|
237
260
|
}
|
|
238
261
|
|
|
262
|
+
async addSiloedNullifiersFromPublic(siloedNullifiers: Fr[]) {
|
|
263
|
+
this.siloedNullifiersFromPublic.push(...siloedNullifiers);
|
|
264
|
+
|
|
265
|
+
await this.addSiloedNullifiers(siloedNullifiers);
|
|
266
|
+
}
|
|
267
|
+
|
|
239
268
|
async addNullifiers(contractAddress: AztecAddress, nullifiers: Fr[]) {
|
|
240
269
|
const siloedNullifiers = nullifiers.map(nullifier => siloNullifier(contractAddress, nullifier));
|
|
241
270
|
await this.addSiloedNullifiers(siloedNullifiers);
|
|
242
271
|
}
|
|
243
272
|
|
|
244
|
-
async
|
|
273
|
+
async addUniqueNoteHashes(siloedNoteHashes: Fr[]) {
|
|
245
274
|
const db = await this.trees.getLatest();
|
|
246
275
|
await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, siloedNoteHashes);
|
|
247
276
|
}
|
|
277
|
+
|
|
278
|
+
async addUniqueNoteHashesFromPublic(siloedNoteHashes: Fr[]) {
|
|
279
|
+
this.uniqueNoteHashesFromPublic.push(...siloedNoteHashes);
|
|
280
|
+
await this.addUniqueNoteHashes(siloedNoteHashes);
|
|
281
|
+
}
|
|
282
|
+
|
|
248
283
|
async addNoteHashes(contractAddress: AztecAddress, noteHashes: Fr[]) {
|
|
249
284
|
const siloedNoteHashes = noteHashes.map(noteHash => siloNoteHash(contractAddress, noteHash));
|
|
250
|
-
|
|
285
|
+
|
|
286
|
+
await this.addUniqueNoteHashes(siloedNoteHashes);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
addPrivateLogs(contractAddress: AztecAddress, privateLogs: PrivateLog[]) {
|
|
290
|
+
privateLogs.forEach(privateLog => {
|
|
291
|
+
privateLog.fields[0] = poseidon2Hash([contractAddress, privateLog.fields[0]]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
this.privateLogs.push(...privateLogs);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
addPublicLogs(logs: UnencryptedL2Log[]) {
|
|
298
|
+
logs.forEach(log => {
|
|
299
|
+
if (log.data.length < 32 * 33) {
|
|
300
|
+
// TODO remove when #9835 and #9836 are fixed
|
|
301
|
+
this.logger.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
// TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields.
|
|
306
|
+
// This means that for every 32 bytes of payload, we only have 1 byte of data.
|
|
307
|
+
// Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32.
|
|
308
|
+
const correctedBuffer = Buffer.alloc(32);
|
|
309
|
+
const initialOffset = 32;
|
|
310
|
+
for (let i = 0; i < 32; i++) {
|
|
311
|
+
const byte = Fr.fromBuffer(log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset)).toNumber();
|
|
312
|
+
correctedBuffer.writeUInt8(byte, i);
|
|
313
|
+
}
|
|
314
|
+
const tag = new Fr(correctedBuffer);
|
|
315
|
+
|
|
316
|
+
this.logger.verbose(`Found tagged unencrypted log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
317
|
+
this.publicLogs.push(log);
|
|
318
|
+
} catch (err) {
|
|
319
|
+
this.logger.warn(`Failed to add tagged log to store: ${err}`);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
251
322
|
}
|
|
252
323
|
|
|
253
324
|
// TypedOracle
|
|
@@ -298,11 +369,13 @@ export class TXE implements TypedOracle {
|
|
|
298
369
|
|
|
299
370
|
async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
|
|
300
371
|
const db = await this.#getTreesAt(blockNumber);
|
|
372
|
+
|
|
301
373
|
const index = await db.findLeafIndex(treeId, leafValue.toBuffer());
|
|
302
|
-
if (
|
|
374
|
+
if (index === undefined) {
|
|
303
375
|
throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
|
|
304
376
|
}
|
|
305
377
|
const siblingPath = await db.getSiblingPath(treeId, index);
|
|
378
|
+
|
|
306
379
|
return [new Fr(index), ...siblingPath.toFields()];
|
|
307
380
|
}
|
|
308
381
|
|
|
@@ -355,15 +428,30 @@ export class TXE implements TypedOracle {
|
|
|
355
428
|
}
|
|
356
429
|
}
|
|
357
430
|
|
|
358
|
-
getLowNullifierMembershipWitness(
|
|
359
|
-
|
|
360
|
-
|
|
431
|
+
async getLowNullifierMembershipWitness(
|
|
432
|
+
blockNumber: number,
|
|
433
|
+
nullifier: Fr,
|
|
361
434
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
362
|
-
|
|
435
|
+
const committedDb = await this.#getTreesAt(blockNumber);
|
|
436
|
+
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
437
|
+
if (!findResult) {
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
const { index, alreadyPresent } = findResult;
|
|
441
|
+
if (alreadyPresent) {
|
|
442
|
+
this.logger.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
|
|
443
|
+
}
|
|
444
|
+
const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!;
|
|
445
|
+
|
|
446
|
+
const siblingPath = await committedDb.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
|
|
447
|
+
MerkleTreeId.NULLIFIER_TREE,
|
|
448
|
+
BigInt(index),
|
|
449
|
+
);
|
|
450
|
+
return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
|
|
363
451
|
}
|
|
364
452
|
|
|
365
|
-
async
|
|
366
|
-
const header =
|
|
453
|
+
async getBlockHeader(blockNumber: number): Promise<BlockHeader | undefined> {
|
|
454
|
+
const header = BlockHeader.empty();
|
|
367
455
|
const db = await this.#getTreesAt(blockNumber);
|
|
368
456
|
header.state = await db.getStateReference();
|
|
369
457
|
header.globalVariables.blockNumber = new Fr(blockNumber);
|
|
@@ -382,7 +470,7 @@ export class TXE implements TypedOracle {
|
|
|
382
470
|
throw new Error('Method not implemented.');
|
|
383
471
|
}
|
|
384
472
|
|
|
385
|
-
getNotes(
|
|
473
|
+
async getNotes(
|
|
386
474
|
storageSlot: Fr,
|
|
387
475
|
numSelects: number,
|
|
388
476
|
selectByIndexes: number[],
|
|
@@ -398,10 +486,12 @@ export class TXE implements TypedOracle {
|
|
|
398
486
|
offset: number,
|
|
399
487
|
_status: NoteStatus,
|
|
400
488
|
) {
|
|
401
|
-
|
|
489
|
+
const syncedNotes = await this.simulatorOracle.getNotes(this.contractAddress, storageSlot, _status);
|
|
402
490
|
const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
|
|
403
491
|
|
|
404
|
-
const
|
|
492
|
+
const notesToFilter = [...pendingNotes, ...syncedNotes];
|
|
493
|
+
|
|
494
|
+
const notes = pickNotes<NoteData>(notesToFilter, {
|
|
405
495
|
selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
|
|
406
496
|
selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
|
|
407
497
|
value: selectValues[i],
|
|
@@ -421,10 +511,10 @@ export class TXE implements TypedOracle {
|
|
|
421
511
|
.join(', ')}`,
|
|
422
512
|
);
|
|
423
513
|
|
|
424
|
-
return
|
|
514
|
+
return notes;
|
|
425
515
|
}
|
|
426
516
|
|
|
427
|
-
notifyCreatedNote(storageSlot: Fr,
|
|
517
|
+
notifyCreatedNote(storageSlot: Fr, _noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
|
|
428
518
|
const note = new Note(noteItems);
|
|
429
519
|
this.noteCache.addNewNote(
|
|
430
520
|
{
|
|
@@ -506,6 +596,52 @@ export class TXE implements TypedOracle {
|
|
|
506
596
|
return publicDataWrites.map(write => write.value);
|
|
507
597
|
}
|
|
508
598
|
|
|
599
|
+
async commitState() {
|
|
600
|
+
const blockNumber = await this.getBlockNumber();
|
|
601
|
+
if (this.committedBlocks.has(blockNumber)) {
|
|
602
|
+
throw new Error('Already committed state');
|
|
603
|
+
} else {
|
|
604
|
+
this.committedBlocks.add(blockNumber);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const txEffect = TxEffect.empty();
|
|
608
|
+
|
|
609
|
+
let i = 0;
|
|
610
|
+
txEffect.noteHashes = [
|
|
611
|
+
...this.noteCache
|
|
612
|
+
.getAllNotes()
|
|
613
|
+
.map(pendingNote =>
|
|
614
|
+
computeUniqueNoteHash(
|
|
615
|
+
computeNoteHashNonce(new Fr(this.blockNumber + 6969), i++),
|
|
616
|
+
siloNoteHash(pendingNote.note.contractAddress, pendingNote.noteHashForConsumption),
|
|
617
|
+
),
|
|
618
|
+
),
|
|
619
|
+
...this.uniqueNoteHashesFromPublic,
|
|
620
|
+
];
|
|
621
|
+
txEffect.nullifiers = [new Fr(blockNumber + 6969), ...this.noteCache.getAllNullifiers()];
|
|
622
|
+
|
|
623
|
+
// Using block number itself, (without adding 6969) gets killed at 1 as it says the slot is already used,
|
|
624
|
+
// it seems like we commit a 1 there to the trees before ? To see what I mean, uncomment these lines below
|
|
625
|
+
// let index = await (await this.trees.getLatest()).findLeafIndex(MerkleTreeId.NULLIFIER_TREE, Fr.ONE.toBuffer());
|
|
626
|
+
// console.log('INDEX OF ONE', index);
|
|
627
|
+
// index = await (await this.trees.getLatest()).findLeafIndex(MerkleTreeId.NULLIFIER_TREE, Fr.random().toBuffer());
|
|
628
|
+
// console.log('INDEX OF RANDOM', index);
|
|
629
|
+
|
|
630
|
+
this.node.setTxEffect(blockNumber, new TxHash(new Fr(blockNumber).toBuffer()), txEffect);
|
|
631
|
+
this.node.setNullifiersIndexesWithBlock(blockNumber, txEffect.nullifiers);
|
|
632
|
+
this.node.addNoteLogsByTags(this.blockNumber, this.privateLogs);
|
|
633
|
+
this.node.addPublicLogsByTags(this.blockNumber, this.publicLogs);
|
|
634
|
+
|
|
635
|
+
await this.addUniqueNoteHashes(txEffect.noteHashes);
|
|
636
|
+
await this.addSiloedNullifiers(txEffect.nullifiers);
|
|
637
|
+
|
|
638
|
+
this.privateLogs = [];
|
|
639
|
+
this.publicLogs = [];
|
|
640
|
+
this.uniqueNoteHashesFromPublic = [];
|
|
641
|
+
this.siloedNullifiersFromPublic = [];
|
|
642
|
+
this.noteCache = new ExecutionNoteCache(new Fr(1));
|
|
643
|
+
}
|
|
644
|
+
|
|
509
645
|
emitContractClassLog(_log: UnencryptedL2Log, _counter: number): Fr {
|
|
510
646
|
throw new Error('Method not implemented.');
|
|
511
647
|
}
|
|
@@ -570,14 +706,9 @@ export class TXE implements TypedOracle {
|
|
|
570
706
|
const endSideEffectCounter = publicInputs.endSideEffectCounter;
|
|
571
707
|
this.sideEffectCounter = endSideEffectCounter.toNumber() + 1;
|
|
572
708
|
|
|
573
|
-
|
|
709
|
+
this.addPrivateLogs(
|
|
574
710
|
targetContractAddress,
|
|
575
|
-
publicInputs.
|
|
576
|
-
);
|
|
577
|
-
|
|
578
|
-
await this.addNoteHashes(
|
|
579
|
-
targetContractAddress,
|
|
580
|
-
publicInputs.noteHashes.filter(noteHash => !noteHash.isEmpty()).map(noteHash => noteHash.value),
|
|
711
|
+
publicInputs.privateLogs.filter(privateLog => !privateLog.isEmpty()).map(privateLog => privateLog.log),
|
|
581
712
|
);
|
|
582
713
|
|
|
583
714
|
this.setContractAddress(currentContractAddress);
|
|
@@ -634,6 +765,7 @@ export class TXE implements TypedOracle {
|
|
|
634
765
|
const executionRequest = new PublicExecutionRequest(callContext, args);
|
|
635
766
|
|
|
636
767
|
const db = await this.trees.getLatest();
|
|
768
|
+
const worldStateDb = new TXEWorldStateDB(db, new TXEPublicContractDataSource(this));
|
|
637
769
|
|
|
638
770
|
const globalVariables = GlobalVariables.empty();
|
|
639
771
|
globalVariables.chainId = this.chainId;
|
|
@@ -641,12 +773,23 @@ export class TXE implements TypedOracle {
|
|
|
641
773
|
globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
642
774
|
globalVariables.gasFees = new GasFees(1, 1);
|
|
643
775
|
|
|
776
|
+
// If the contract instance exists in the TXE's world state, make sure its nullifier is present in the tree
|
|
777
|
+
// so its nullifier check passes.
|
|
778
|
+
if ((await worldStateDb.getContractInstance(callContext.contractAddress)) !== undefined) {
|
|
779
|
+
const contractAddressNullifier = siloNullifier(
|
|
780
|
+
AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
|
|
781
|
+
callContext.contractAddress.toField(),
|
|
782
|
+
);
|
|
783
|
+
if ((await worldStateDb.getNullifierIndex(contractAddressNullifier)) === undefined) {
|
|
784
|
+
await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [contractAddressNullifier.toBuffer()], 0);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
644
788
|
const simulator = new PublicTxSimulator(
|
|
645
789
|
db,
|
|
646
790
|
new TXEWorldStateDB(db, new TXEPublicContractDataSource(this)),
|
|
647
791
|
new NoopTelemetryClient(),
|
|
648
792
|
globalVariables,
|
|
649
|
-
/*realAvmProvingRequests=*/ false,
|
|
650
793
|
);
|
|
651
794
|
|
|
652
795
|
// When setting up a teardown call, we tell it that
|
|
@@ -655,6 +798,9 @@ export class TXE implements TypedOracle {
|
|
|
655
798
|
const tx = createTxForPublicCall(executionRequest, gasUsedByPrivate, isTeardown);
|
|
656
799
|
|
|
657
800
|
const result = await simulator.simulate(tx);
|
|
801
|
+
|
|
802
|
+
this.addPublicLogs(tx.unencryptedLogs.unrollLogs());
|
|
803
|
+
|
|
658
804
|
return Promise.resolve(result);
|
|
659
805
|
}
|
|
660
806
|
|
|
@@ -707,7 +853,7 @@ export class TXE implements TypedOracle {
|
|
|
707
853
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
708
854
|
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty());
|
|
709
855
|
await this.addPublicDataWrites(publicDataWrites);
|
|
710
|
-
await this.
|
|
856
|
+
await this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
711
857
|
await this.addSiloedNullifiers(nullifiers);
|
|
712
858
|
|
|
713
859
|
this.setContractAddress(currentContractAddress);
|
|
@@ -741,7 +887,7 @@ export class TXE implements TypedOracle {
|
|
|
741
887
|
}
|
|
742
888
|
|
|
743
889
|
debugLog(message: string, fields: Fr[]): void {
|
|
744
|
-
this.logger.verbose(
|
|
890
|
+
this.logger.verbose(`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
|
|
745
891
|
}
|
|
746
892
|
|
|
747
893
|
async incrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<void> {
|
|
@@ -765,8 +911,17 @@ export class TXE implements TypedOracle {
|
|
|
765
911
|
return siloedSecret;
|
|
766
912
|
}
|
|
767
913
|
|
|
768
|
-
syncNotes() {
|
|
769
|
-
|
|
914
|
+
async syncNotes() {
|
|
915
|
+
const taggedLogsByRecipient = await this.simulatorOracle.syncTaggedLogs(
|
|
916
|
+
this.contractAddress,
|
|
917
|
+
await this.getBlockNumber(),
|
|
918
|
+
undefined,
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) {
|
|
922
|
+
await this.simulatorOracle.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient));
|
|
923
|
+
}
|
|
924
|
+
|
|
770
925
|
return Promise.resolve();
|
|
771
926
|
}
|
|
772
927
|
|
|
@@ -797,7 +952,7 @@ export class TXE implements TypedOracle {
|
|
|
797
952
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
798
953
|
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty());
|
|
799
954
|
await this.addPublicDataWrites(publicDataWrites);
|
|
800
|
-
await this.
|
|
955
|
+
await this.addUniqueNoteHashes(noteHashes);
|
|
801
956
|
await this.addSiloedNullifiers(nullifiers);
|
|
802
957
|
}
|
|
803
958
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
|
|
2
2
|
import { L2Block, MerkleTreeId, SimulationError } from '@aztec/circuit-types';
|
|
3
3
|
import {
|
|
4
|
+
BlockHeader,
|
|
4
5
|
Fr,
|
|
5
6
|
FunctionSelector,
|
|
6
|
-
Header,
|
|
7
7
|
PublicDataTreeLeaf,
|
|
8
8
|
PublicKeys,
|
|
9
9
|
computePartialAddress,
|
|
@@ -14,7 +14,7 @@ import { type ContractArtifact, NoteSelector } from '@aztec/foundation/abi';
|
|
|
14
14
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
15
15
|
import { type Logger } from '@aztec/foundation/log';
|
|
16
16
|
import { KeyStore } from '@aztec/key-store';
|
|
17
|
-
import { openTmpStore } from '@aztec/kv-store/
|
|
17
|
+
import { openTmpStore } from '@aztec/kv-store/lmdb';
|
|
18
18
|
import { getCanonicalProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
|
|
19
19
|
import { enrichPublicSimulationError } from '@aztec/pxe';
|
|
20
20
|
import { ExecutionNoteCache, PackedValuesCache, type TypedOracle } from '@aztec/simulator';
|
|
@@ -70,9 +70,12 @@ export class TXEService {
|
|
|
70
70
|
const nBlocks = fromSingle(blocks).toNumber();
|
|
71
71
|
this.logger.debug(`time traveling ${nBlocks} blocks`);
|
|
72
72
|
const trees = (this.typedOracle as TXE).getTrees();
|
|
73
|
+
|
|
74
|
+
await (this.typedOracle as TXE).commitState();
|
|
75
|
+
|
|
73
76
|
for (let i = 0; i < nBlocks; i++) {
|
|
74
77
|
const blockNumber = await this.typedOracle.getBlockNumber();
|
|
75
|
-
const header =
|
|
78
|
+
const header = BlockHeader.empty();
|
|
76
79
|
const l2Block = L2Block.empty();
|
|
77
80
|
header.state = await trees.getStateReference(true);
|
|
78
81
|
header.globalVariables.blockNumber = new Fr(blockNumber);
|
|
@@ -550,8 +553,8 @@ export class TXEService {
|
|
|
550
553
|
return toForeignCallResult([]);
|
|
551
554
|
}
|
|
552
555
|
|
|
553
|
-
async
|
|
554
|
-
const header = await this.typedOracle.
|
|
556
|
+
async getBlockHeader(blockNumber: ForeignCallSingle) {
|
|
557
|
+
const header = await this.typedOracle.getBlockHeader(fromSingle(blockNumber).toNumber());
|
|
555
558
|
if (!header) {
|
|
556
559
|
throw new Error(`Block header not found for block ${blockNumber}.`);
|
|
557
560
|
}
|
|
@@ -571,6 +574,16 @@ export class TXEService {
|
|
|
571
574
|
return toForeignCallResult([toArray(witness)]);
|
|
572
575
|
}
|
|
573
576
|
|
|
577
|
+
async getLowNullifierMembershipWitness(blockNumber: ForeignCallSingle, nullifier: ForeignCallSingle) {
|
|
578
|
+
const parsedBlockNumber = fromSingle(blockNumber).toNumber();
|
|
579
|
+
|
|
580
|
+
const witness = await this.typedOracle.getLowNullifierMembershipWitness(parsedBlockNumber, fromSingle(nullifier));
|
|
581
|
+
if (!witness) {
|
|
582
|
+
throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${parsedBlockNumber}.`);
|
|
583
|
+
}
|
|
584
|
+
return toForeignCallResult([toArray(witness.toFields())]);
|
|
585
|
+
}
|
|
586
|
+
|
|
574
587
|
async getAppTaggingSecretAsSender(sender: ForeignCallSingle, recipient: ForeignCallSingle) {
|
|
575
588
|
const secret = await this.typedOracle.getAppTaggingSecretAsSender(
|
|
576
589
|
AztecAddress.fromField(fromSingle(sender)),
|
package/src/util/txe_database.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { type AztecAddress, CompleteAddress } from '@aztec/circuits.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type AztecAsyncKVStore, type AztecAsyncMap } from '@aztec/kv-store';
|
|
3
3
|
import { KVPxeDatabase } from '@aztec/pxe';
|
|
4
4
|
|
|
5
5
|
export class TXEDatabase extends KVPxeDatabase {
|
|
6
|
-
#accounts:
|
|
6
|
+
#accounts: AztecAsyncMap<string, Buffer>;
|
|
7
7
|
|
|
8
|
-
constructor(db:
|
|
8
|
+
constructor(db: AztecAsyncKVStore) {
|
|
9
9
|
super(db);
|
|
10
10
|
this.#accounts = db.openMap('accounts');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
getAccount(key: AztecAddress) {
|
|
14
|
-
const completeAddress = this.#accounts.
|
|
13
|
+
async getAccount(key: AztecAddress) {
|
|
14
|
+
const completeAddress = await this.#accounts.getAsync(key.toString());
|
|
15
15
|
if (!completeAddress) {
|
|
16
16
|
throw new Error(`Account not found: ${key.toString()}`);
|
|
17
17
|
}
|
|
@@ -20,5 +20,6 @@ export class TXEDatabase extends KVPxeDatabase {
|
|
|
20
20
|
|
|
21
21
|
async setAccount(key: AztecAddress, value: CompleteAddress) {
|
|
22
22
|
await this.#accounts.set(key.toString(), value.toBuffer());
|
|
23
|
+
await this.addCompleteAddress(value);
|
|
23
24
|
}
|
|
24
25
|
}
|