@aztec/txe 0.65.2 → 0.67.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/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 -13
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +134 -44
- package/dest/txe_service/txe_service.d.ts +3 -19
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +14 -25
- 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 +19 -16
- package/src/bin/index.ts +2 -2
- package/src/node/txe_node.ts +666 -0
- package/src/oracle/txe_oracle.ts +183 -56
- package/src/txe_service/txe_service.ts +16 -37
- package/src/util/txe_database.ts +6 -5
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AuthWitness,
|
|
3
|
-
type EncryptedL2NoteLog,
|
|
4
3
|
MerkleTreeId,
|
|
5
4
|
Note,
|
|
6
5
|
type NoteStatus,
|
|
@@ -8,17 +7,20 @@ import {
|
|
|
8
7
|
PublicDataWitness,
|
|
9
8
|
PublicExecutionRequest,
|
|
10
9
|
SimulationError,
|
|
10
|
+
TxEffect,
|
|
11
|
+
TxHash,
|
|
11
12
|
type UnencryptedL2Log,
|
|
12
13
|
} from '@aztec/circuit-types';
|
|
13
14
|
import { type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
|
|
14
15
|
import {
|
|
16
|
+
BlockHeader,
|
|
15
17
|
CallContext,
|
|
16
18
|
type ContractInstance,
|
|
17
19
|
type ContractInstanceWithAddress,
|
|
20
|
+
DEPLOYER_CONTRACT_ADDRESS,
|
|
18
21
|
Gas,
|
|
19
22
|
GasFees,
|
|
20
23
|
GlobalVariables,
|
|
21
|
-
Header,
|
|
22
24
|
IndexedTaggingSecret,
|
|
23
25
|
type KeyValidationRequest,
|
|
24
26
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
@@ -29,6 +31,7 @@ import {
|
|
|
29
31
|
type PUBLIC_DATA_TREE_HEIGHT,
|
|
30
32
|
PUBLIC_DISPATCH_SELECTOR,
|
|
31
33
|
PrivateContextInputs,
|
|
34
|
+
type PrivateLog,
|
|
32
35
|
PublicDataTreeLeaf,
|
|
33
36
|
type PublicDataTreeLeafPreimage,
|
|
34
37
|
type PublicDataWrite,
|
|
@@ -38,7 +41,13 @@ import {
|
|
|
38
41
|
getContractClassFromArtifact,
|
|
39
42
|
} from '@aztec/circuits.js';
|
|
40
43
|
import { Schnorr } from '@aztec/circuits.js/barretenberg';
|
|
41
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
computeNoteHashNonce,
|
|
46
|
+
computePublicDataTreeLeafSlot,
|
|
47
|
+
computeUniqueNoteHash,
|
|
48
|
+
siloNoteHash,
|
|
49
|
+
siloNullifier,
|
|
50
|
+
} from '@aztec/circuits.js/hash';
|
|
42
51
|
import {
|
|
43
52
|
type ContractArtifact,
|
|
44
53
|
type FunctionAbi,
|
|
@@ -52,10 +61,10 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
52
61
|
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
53
62
|
import { Timer } from '@aztec/foundation/timer';
|
|
54
63
|
import { type KeyStore } from '@aztec/key-store';
|
|
55
|
-
import { ContractDataOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
64
|
+
import { ContractDataOracle, SimulatorOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
56
65
|
import {
|
|
57
66
|
ExecutionError,
|
|
58
|
-
|
|
67
|
+
ExecutionNoteCache,
|
|
59
68
|
type MessageLoadOracleInputs,
|
|
60
69
|
type NoteData,
|
|
61
70
|
Oracle,
|
|
@@ -76,6 +85,7 @@ import { createTxForPublicCall } from '@aztec/simulator/public/fixtures';
|
|
|
76
85
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
77
86
|
import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
|
|
78
87
|
|
|
88
|
+
import { TXENode } from '../node/txe_node.js';
|
|
79
89
|
import { type TXEDatabase } from '../util/txe_database.js';
|
|
80
90
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
81
91
|
import { TXEWorldStateDB } from '../util/txe_world_state_db.js';
|
|
@@ -91,11 +101,19 @@ export class TXE implements TypedOracle {
|
|
|
91
101
|
private nestedCallReturndata: Fr[] = [];
|
|
92
102
|
|
|
93
103
|
private contractDataOracle: ContractDataOracle;
|
|
104
|
+
private simulatorOracle: SimulatorOracle;
|
|
94
105
|
|
|
95
106
|
private version: Fr = Fr.ONE;
|
|
96
107
|
private chainId: Fr = Fr.ONE;
|
|
97
108
|
|
|
98
|
-
private
|
|
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);
|
|
99
117
|
|
|
100
118
|
constructor(
|
|
101
119
|
private logger: Logger,
|
|
@@ -109,6 +127,7 @@ export class TXE implements TypedOracle {
|
|
|
109
127
|
this.contractAddress = AztecAddress.random();
|
|
110
128
|
// Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404)
|
|
111
129
|
this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE);
|
|
130
|
+
this.simulatorOracle = new SimulatorOracle(this.contractDataOracle, txeDatabase, keyStore, this.node);
|
|
112
131
|
}
|
|
113
132
|
|
|
114
133
|
// Utils
|
|
@@ -159,6 +178,7 @@ export class TXE implements TypedOracle {
|
|
|
159
178
|
|
|
160
179
|
setBlockNumber(blockNumber: number) {
|
|
161
180
|
this.blockNumber = blockNumber;
|
|
181
|
+
this.node.setBlockNumber(blockNumber);
|
|
162
182
|
}
|
|
163
183
|
|
|
164
184
|
getTrees() {
|
|
@@ -213,7 +233,7 @@ export class TXE implements TypedOracle {
|
|
|
213
233
|
}
|
|
214
234
|
|
|
215
235
|
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
216
|
-
const account = this.txeDatabase.getAccount(address);
|
|
236
|
+
const account = await this.txeDatabase.getAccount(address);
|
|
217
237
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
218
238
|
const schnorr = new Schnorr();
|
|
219
239
|
const signature = schnorr.constructSignature(messageHash.toBuffer(), privateKey).toBuffer();
|
|
@@ -239,18 +259,66 @@ export class TXE implements TypedOracle {
|
|
|
239
259
|
);
|
|
240
260
|
}
|
|
241
261
|
|
|
262
|
+
async addSiloedNullifiersFromPublic(siloedNullifiers: Fr[]) {
|
|
263
|
+
this.siloedNullifiersFromPublic.push(...siloedNullifiers);
|
|
264
|
+
|
|
265
|
+
await this.addSiloedNullifiers(siloedNullifiers);
|
|
266
|
+
}
|
|
267
|
+
|
|
242
268
|
async addNullifiers(contractAddress: AztecAddress, nullifiers: Fr[]) {
|
|
243
269
|
const siloedNullifiers = nullifiers.map(nullifier => siloNullifier(contractAddress, nullifier));
|
|
244
270
|
await this.addSiloedNullifiers(siloedNullifiers);
|
|
245
271
|
}
|
|
246
272
|
|
|
247
|
-
async
|
|
273
|
+
async addUniqueNoteHashes(siloedNoteHashes: Fr[]) {
|
|
248
274
|
const db = await this.trees.getLatest();
|
|
249
275
|
await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, siloedNoteHashes);
|
|
250
276
|
}
|
|
277
|
+
|
|
278
|
+
async addUniqueNoteHashesFromPublic(siloedNoteHashes: Fr[]) {
|
|
279
|
+
this.uniqueNoteHashesFromPublic.push(...siloedNoteHashes);
|
|
280
|
+
await this.addUniqueNoteHashes(siloedNoteHashes);
|
|
281
|
+
}
|
|
282
|
+
|
|
251
283
|
async addNoteHashes(contractAddress: AztecAddress, noteHashes: Fr[]) {
|
|
252
284
|
const siloedNoteHashes = noteHashes.map(noteHash => siloNoteHash(contractAddress, noteHash));
|
|
253
|
-
|
|
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
|
+
});
|
|
254
322
|
}
|
|
255
323
|
|
|
256
324
|
// TypedOracle
|
|
@@ -301,11 +369,13 @@ export class TXE implements TypedOracle {
|
|
|
301
369
|
|
|
302
370
|
async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
|
|
303
371
|
const db = await this.#getTreesAt(blockNumber);
|
|
372
|
+
|
|
304
373
|
const index = await db.findLeafIndex(treeId, leafValue.toBuffer());
|
|
305
|
-
if (
|
|
374
|
+
if (index === undefined) {
|
|
306
375
|
throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
|
|
307
376
|
}
|
|
308
377
|
const siblingPath = await db.getSiblingPath(treeId, index);
|
|
378
|
+
|
|
309
379
|
return [new Fr(index), ...siblingPath.toFields()];
|
|
310
380
|
}
|
|
311
381
|
|
|
@@ -358,15 +428,30 @@ export class TXE implements TypedOracle {
|
|
|
358
428
|
}
|
|
359
429
|
}
|
|
360
430
|
|
|
361
|
-
getLowNullifierMembershipWitness(
|
|
362
|
-
|
|
363
|
-
|
|
431
|
+
async getLowNullifierMembershipWitness(
|
|
432
|
+
blockNumber: number,
|
|
433
|
+
nullifier: Fr,
|
|
364
434
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
365
|
-
|
|
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);
|
|
366
451
|
}
|
|
367
452
|
|
|
368
|
-
async
|
|
369
|
-
const header =
|
|
453
|
+
async getBlockHeader(blockNumber: number): Promise<BlockHeader | undefined> {
|
|
454
|
+
const header = BlockHeader.empty();
|
|
370
455
|
const db = await this.#getTreesAt(blockNumber);
|
|
371
456
|
header.state = await db.getStateReference();
|
|
372
457
|
header.globalVariables.blockNumber = new Fr(blockNumber);
|
|
@@ -385,7 +470,7 @@ export class TXE implements TypedOracle {
|
|
|
385
470
|
throw new Error('Method not implemented.');
|
|
386
471
|
}
|
|
387
472
|
|
|
388
|
-
getNotes(
|
|
473
|
+
async getNotes(
|
|
389
474
|
storageSlot: Fr,
|
|
390
475
|
numSelects: number,
|
|
391
476
|
selectByIndexes: number[],
|
|
@@ -401,10 +486,12 @@ export class TXE implements TypedOracle {
|
|
|
401
486
|
offset: number,
|
|
402
487
|
_status: NoteStatus,
|
|
403
488
|
) {
|
|
404
|
-
|
|
489
|
+
const syncedNotes = await this.simulatorOracle.getNotes(this.contractAddress, storageSlot, _status);
|
|
405
490
|
const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
|
|
406
491
|
|
|
407
|
-
const
|
|
492
|
+
const notesToFilter = [...pendingNotes, ...syncedNotes];
|
|
493
|
+
|
|
494
|
+
const notes = pickNotes<NoteData>(notesToFilter, {
|
|
408
495
|
selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
|
|
409
496
|
selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
|
|
410
497
|
value: selectValues[i],
|
|
@@ -424,10 +511,10 @@ export class TXE implements TypedOracle {
|
|
|
424
511
|
.join(', ')}`,
|
|
425
512
|
);
|
|
426
513
|
|
|
427
|
-
return
|
|
514
|
+
return notes;
|
|
428
515
|
}
|
|
429
516
|
|
|
430
|
-
notifyCreatedNote(storageSlot: Fr,
|
|
517
|
+
notifyCreatedNote(storageSlot: Fr, _noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
|
|
431
518
|
const note = new Note(noteItems);
|
|
432
519
|
this.noteCache.addNewNote(
|
|
433
520
|
{
|
|
@@ -509,19 +596,50 @@ export class TXE implements TypedOracle {
|
|
|
509
596
|
return publicDataWrites.map(write => write.value);
|
|
510
597
|
}
|
|
511
598
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
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
|
+
}
|
|
521
606
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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));
|
|
525
643
|
}
|
|
526
644
|
|
|
527
645
|
emitContractClassLog(_log: UnencryptedL2Log, _counter: number): Fr {
|
|
@@ -588,14 +706,9 @@ export class TXE implements TypedOracle {
|
|
|
588
706
|
const endSideEffectCounter = publicInputs.endSideEffectCounter;
|
|
589
707
|
this.sideEffectCounter = endSideEffectCounter.toNumber() + 1;
|
|
590
708
|
|
|
591
|
-
|
|
592
|
-
targetContractAddress,
|
|
593
|
-
publicInputs.nullifiers.filter(nullifier => !nullifier.isEmpty()).map(nullifier => nullifier.value),
|
|
594
|
-
);
|
|
595
|
-
|
|
596
|
-
await this.addNoteHashes(
|
|
709
|
+
this.addPrivateLogs(
|
|
597
710
|
targetContractAddress,
|
|
598
|
-
publicInputs.
|
|
711
|
+
publicInputs.privateLogs.filter(privateLog => !privateLog.isEmpty()).map(privateLog => privateLog.log),
|
|
599
712
|
);
|
|
600
713
|
|
|
601
714
|
this.setContractAddress(currentContractAddress);
|
|
@@ -652,6 +765,7 @@ export class TXE implements TypedOracle {
|
|
|
652
765
|
const executionRequest = new PublicExecutionRequest(callContext, args);
|
|
653
766
|
|
|
654
767
|
const db = await this.trees.getLatest();
|
|
768
|
+
const worldStateDb = new TXEWorldStateDB(db, new TXEPublicContractDataSource(this));
|
|
655
769
|
|
|
656
770
|
const globalVariables = GlobalVariables.empty();
|
|
657
771
|
globalVariables.chainId = this.chainId;
|
|
@@ -659,12 +773,23 @@ export class TXE implements TypedOracle {
|
|
|
659
773
|
globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
660
774
|
globalVariables.gasFees = new GasFees(1, 1);
|
|
661
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
|
+
|
|
662
788
|
const simulator = new PublicTxSimulator(
|
|
663
789
|
db,
|
|
664
790
|
new TXEWorldStateDB(db, new TXEPublicContractDataSource(this)),
|
|
665
791
|
new NoopTelemetryClient(),
|
|
666
792
|
globalVariables,
|
|
667
|
-
/*realAvmProvingRequests=*/ false,
|
|
668
793
|
);
|
|
669
794
|
|
|
670
795
|
// When setting up a teardown call, we tell it that
|
|
@@ -673,6 +798,9 @@ export class TXE implements TypedOracle {
|
|
|
673
798
|
const tx = createTxForPublicCall(executionRequest, gasUsedByPrivate, isTeardown);
|
|
674
799
|
|
|
675
800
|
const result = await simulator.simulate(tx);
|
|
801
|
+
|
|
802
|
+
this.addPublicLogs(tx.unencryptedLogs.unrollLogs());
|
|
803
|
+
|
|
676
804
|
return Promise.resolve(result);
|
|
677
805
|
}
|
|
678
806
|
|
|
@@ -725,7 +853,7 @@ export class TXE implements TypedOracle {
|
|
|
725
853
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
726
854
|
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty());
|
|
727
855
|
await this.addPublicDataWrites(publicDataWrites);
|
|
728
|
-
await this.
|
|
856
|
+
await this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
729
857
|
await this.addSiloedNullifiers(nullifiers);
|
|
730
858
|
|
|
731
859
|
this.setContractAddress(currentContractAddress);
|
|
@@ -759,17 +887,7 @@ export class TXE implements TypedOracle {
|
|
|
759
887
|
}
|
|
760
888
|
|
|
761
889
|
debugLog(message: string, fields: Fr[]): void {
|
|
762
|
-
this.logger.verbose(
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
emitEncryptedEventLog(
|
|
766
|
-
_contractAddress: AztecAddress,
|
|
767
|
-
_randomness: Fr,
|
|
768
|
-
_encryptedEvent: Buffer,
|
|
769
|
-
counter: number,
|
|
770
|
-
): void {
|
|
771
|
-
this.sideEffectCounter = counter + 1;
|
|
772
|
-
return;
|
|
890
|
+
this.logger.verbose(`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
|
|
773
891
|
}
|
|
774
892
|
|
|
775
893
|
async incrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<void> {
|
|
@@ -793,8 +911,17 @@ export class TXE implements TypedOracle {
|
|
|
793
911
|
return siloedSecret;
|
|
794
912
|
}
|
|
795
913
|
|
|
796
|
-
syncNotes() {
|
|
797
|
-
|
|
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
|
+
|
|
798
925
|
return Promise.resolve();
|
|
799
926
|
}
|
|
800
927
|
|
|
@@ -825,7 +952,7 @@ export class TXE implements TypedOracle {
|
|
|
825
952
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
826
953
|
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty());
|
|
827
954
|
await this.addPublicDataWrites(publicDataWrites);
|
|
828
|
-
await this.
|
|
955
|
+
await this.addUniqueNoteHashes(noteHashes);
|
|
829
956
|
await this.addSiloedNullifiers(nullifiers);
|
|
830
957
|
}
|
|
831
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);
|
|
@@ -459,30 +462,6 @@ export class TXEService {
|
|
|
459
462
|
return toForeignCallResult([toArray(keyValidationRequest.toFields())]);
|
|
460
463
|
}
|
|
461
464
|
|
|
462
|
-
emitEncryptedLog(
|
|
463
|
-
_contractAddress: ForeignCallSingle,
|
|
464
|
-
_randomness: ForeignCallSingle,
|
|
465
|
-
_encryptedLog: ForeignCallSingle,
|
|
466
|
-
_counter: ForeignCallSingle,
|
|
467
|
-
) {
|
|
468
|
-
// TODO(#8811): Implement
|
|
469
|
-
return toForeignCallResult([]);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
emitEncryptedNoteLog(
|
|
473
|
-
_noteHashCounter: ForeignCallSingle,
|
|
474
|
-
_encryptedNote: ForeignCallArray,
|
|
475
|
-
_counter: ForeignCallSingle,
|
|
476
|
-
) {
|
|
477
|
-
// TODO(#8811): Implement
|
|
478
|
-
return toForeignCallResult([]);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
emitEncryptedEventLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedEvent: Buffer, _counter: number) {
|
|
482
|
-
// TODO(#8811): Implement
|
|
483
|
-
return toForeignCallResult([]);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
465
|
async callPrivateFunction(
|
|
487
466
|
targetContractAddress: ForeignCallSingle,
|
|
488
467
|
functionSelector: ForeignCallSingle,
|
|
@@ -574,8 +553,8 @@ export class TXEService {
|
|
|
574
553
|
return toForeignCallResult([]);
|
|
575
554
|
}
|
|
576
555
|
|
|
577
|
-
async
|
|
578
|
-
const header = await this.typedOracle.
|
|
556
|
+
async getBlockHeader(blockNumber: ForeignCallSingle) {
|
|
557
|
+
const header = await this.typedOracle.getBlockHeader(fromSingle(blockNumber).toNumber());
|
|
579
558
|
if (!header) {
|
|
580
559
|
throw new Error(`Block header not found for block ${blockNumber}.`);
|
|
581
560
|
}
|
|
@@ -595,9 +574,14 @@ export class TXEService {
|
|
|
595
574
|
return toForeignCallResult([toArray(witness)]);
|
|
596
575
|
}
|
|
597
576
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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())]);
|
|
601
585
|
}
|
|
602
586
|
|
|
603
587
|
async getAppTaggingSecretAsSender(sender: ForeignCallSingle, recipient: ForeignCallSingle) {
|
|
@@ -690,11 +674,6 @@ export class TXEService {
|
|
|
690
674
|
return toForeignCallResult([toSingle(new Fr(blockNumber))]);
|
|
691
675
|
}
|
|
692
676
|
|
|
693
|
-
avmOpcodeFunctionSelector() {
|
|
694
|
-
const functionSelector = (this.typedOracle as TXE).getFunctionSelector();
|
|
695
|
-
return toForeignCallResult([toSingle(functionSelector.toField())]);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
677
|
avmOpcodeIsStaticCall() {
|
|
699
678
|
const isStaticCall = (this.typedOracle as TXE).getIsStaticCall();
|
|
700
679
|
return toForeignCallResult([toSingle(new Fr(isStaticCall ? 1 : 0))]);
|
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
|
}
|