@aztec/txe 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.
@@ -0,0 +1,871 @@
1
+ import {
2
+ AuthWitness,
3
+ L1NotePayload,
4
+ MerkleTreeId,
5
+ Note,
6
+ type NoteStatus,
7
+ NullifierMembershipWitness,
8
+ PublicDataWitness,
9
+ PublicDataWrite,
10
+ TaggedLog,
11
+ type UnencryptedL2Log,
12
+ } from '@aztec/circuit-types';
13
+ import { type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
14
+ import {
15
+ CallContext,
16
+ FunctionData,
17
+ Gas,
18
+ GlobalVariables,
19
+ Header,
20
+ type KeyValidationRequest,
21
+ NULLIFIER_SUBTREE_HEIGHT,
22
+ type NULLIFIER_TREE_HEIGHT,
23
+ type NullifierLeafPreimage,
24
+ PUBLIC_DATA_SUBTREE_HEIGHT,
25
+ type PUBLIC_DATA_TREE_HEIGHT,
26
+ PrivateCallStackItem,
27
+ PrivateCircuitPublicInputs,
28
+ PrivateContextInputs,
29
+ PublicCallRequest,
30
+ PublicDataTreeLeaf,
31
+ type PublicDataTreeLeafPreimage,
32
+ TxContext,
33
+ computeContractClassId,
34
+ deriveKeys,
35
+ getContractClassFromArtifact,
36
+ } from '@aztec/circuits.js';
37
+ import { Aes128, Schnorr } from '@aztec/circuits.js/barretenberg';
38
+ import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
39
+ import {
40
+ type ContractArtifact,
41
+ type FunctionAbi,
42
+ FunctionSelector,
43
+ type NoteSelector,
44
+ countArgumentsSize,
45
+ } from '@aztec/foundation/abi';
46
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
47
+ import { Fr, GrumpkinScalar, type Point } from '@aztec/foundation/fields';
48
+ import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
49
+ import { Timer } from '@aztec/foundation/timer';
50
+ import { type KeyStore } from '@aztec/key-store';
51
+ import { ContractDataOracle } from '@aztec/pxe';
52
+ import {
53
+ ContractsDataSourcePublicDB,
54
+ ExecutionError,
55
+ type ExecutionNoteCache,
56
+ type MessageLoadOracleInputs,
57
+ type NoteData,
58
+ Oracle,
59
+ type PackedValuesCache,
60
+ PublicExecutor,
61
+ type TypedOracle,
62
+ WorldStateDB,
63
+ acvm,
64
+ createSimulationError,
65
+ extractCallStack,
66
+ pickNotes,
67
+ toACVMWitness,
68
+ witnessMapToFields,
69
+ } from '@aztec/simulator';
70
+ import { type ContractInstance, type ContractInstanceWithAddress } from '@aztec/types/contracts';
71
+ import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
72
+
73
+ import { type TXEDatabase } from '../util/txe_database.js';
74
+ import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
75
+ import { TXEPublicStateDB } from '../util/txe_public_state_db.js';
76
+
77
+ export class TXE implements TypedOracle {
78
+ private blockNumber = 0;
79
+ private sideEffectsCounter = 0;
80
+ private contractAddress: AztecAddress;
81
+ private msgSender: AztecAddress;
82
+ private functionSelector = FunctionSelector.fromField(new Fr(0));
83
+
84
+ private contractDataOracle: ContractDataOracle;
85
+
86
+ private version: Fr = Fr.ONE;
87
+ private chainId: Fr = Fr.ONE;
88
+
89
+ constructor(
90
+ private logger: Logger,
91
+ private trees: MerkleTrees,
92
+ private packedValuesCache: PackedValuesCache,
93
+ private noteCache: ExecutionNoteCache,
94
+ private keyStore: KeyStore,
95
+ private txeDatabase: TXEDatabase,
96
+ ) {
97
+ this.contractDataOracle = new ContractDataOracle(txeDatabase);
98
+ this.contractAddress = AztecAddress.random();
99
+ this.msgSender = AztecAddress.fromField(new Fr(0));
100
+ }
101
+
102
+ // Utils
103
+
104
+ getChainId() {
105
+ return Promise.resolve(this.chainId);
106
+ }
107
+
108
+ getVersion() {
109
+ return Promise.resolve(this.version);
110
+ }
111
+
112
+ getMsgSender() {
113
+ return this.msgSender;
114
+ }
115
+
116
+ setMsgSender(msgSender: Fr) {
117
+ this.msgSender = msgSender;
118
+ }
119
+
120
+ setFunctionSelector(functionSelector: FunctionSelector) {
121
+ this.functionSelector = functionSelector;
122
+ }
123
+
124
+ getSideEffectsCounter() {
125
+ return this.sideEffectsCounter;
126
+ }
127
+
128
+ setSideEffectsCounter(sideEffectsCounter: number) {
129
+ this.sideEffectsCounter = sideEffectsCounter;
130
+ }
131
+
132
+ setContractAddress(contractAddress: AztecAddress) {
133
+ this.contractAddress = contractAddress;
134
+ }
135
+
136
+ setBlockNumber(blockNumber: number) {
137
+ this.blockNumber = blockNumber;
138
+ }
139
+
140
+ getTrees() {
141
+ return this.trees;
142
+ }
143
+
144
+ getContractDataOracle() {
145
+ return this.contractDataOracle;
146
+ }
147
+
148
+ getTXEDatabase() {
149
+ return this.txeDatabase;
150
+ }
151
+
152
+ getKeyStore() {
153
+ return this.keyStore;
154
+ }
155
+
156
+ async addContractInstance(contractInstance: ContractInstanceWithAddress) {
157
+ await this.txeDatabase.addContractInstance(contractInstance);
158
+ }
159
+
160
+ async addContractArtifact(artifact: ContractArtifact) {
161
+ const contractClass = getContractClassFromArtifact(artifact);
162
+ await this.txeDatabase.addContractArtifact(computeContractClassId(contractClass), artifact);
163
+ }
164
+
165
+ async getPrivateContextInputs(
166
+ blockNumber: number,
167
+ sideEffectsCounter = this.sideEffectsCounter,
168
+ isStaticCall = false,
169
+ isDelegateCall = false,
170
+ ) {
171
+ const trees = this.getTrees();
172
+ const stateReference = await trees.getStateReference(false);
173
+ const inputs = PrivateContextInputs.empty();
174
+ inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
175
+ inputs.historicalHeader.state = stateReference;
176
+ inputs.callContext.msgSender = this.msgSender;
177
+ inputs.callContext.storageContractAddress = this.contractAddress;
178
+ inputs.callContext.sideEffectCounter = sideEffectsCounter;
179
+ inputs.callContext.isStaticCall = isStaticCall;
180
+ inputs.callContext.isDelegateCall = isDelegateCall;
181
+ inputs.startSideEffectCounter = sideEffectsCounter;
182
+ inputs.callContext.functionSelector = this.functionSelector;
183
+ return inputs;
184
+ }
185
+
186
+ getPublicContextInputs() {
187
+ const inputs = {
188
+ functionSelector: FunctionSelector.fromField(new Fr(0)),
189
+ argsHash: new Fr(0),
190
+ isStaticCall: false,
191
+ toFields: function () {
192
+ return [this.functionSelector.toField(), this.argsHash, new Fr(this.isStaticCall)];
193
+ },
194
+ };
195
+ return inputs;
196
+ }
197
+
198
+ async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
199
+ const nullifier = siloNullifier(targetAddress, innerNullifier!);
200
+ const db = this.trees.asLatest();
201
+ const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
202
+ return index !== undefined;
203
+ }
204
+
205
+ async avmOpcodeEmitNullifier(nullifier: Fr) {
206
+ const db = this.trees.asLatest();
207
+ const siloedNullifier = siloNullifier(this.contractAddress, nullifier);
208
+ await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()], NULLIFIER_SUBTREE_HEIGHT);
209
+ return Promise.resolve();
210
+ }
211
+
212
+ async avmOpcodeEmitNoteHash(innerNoteHash: Fr) {
213
+ const db = this.trees.asLatest();
214
+ const noteHash = siloNoteHash(this.contractAddress, innerNoteHash);
215
+ await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [noteHash]);
216
+ return Promise.resolve();
217
+ }
218
+
219
+ deriveKeys(secret: Fr) {
220
+ return deriveKeys(secret);
221
+ }
222
+
223
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
224
+ const account = this.txeDatabase.getAccount(address);
225
+ const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
226
+ const schnorr = new Schnorr();
227
+ const signature = schnorr.constructSignature(messageHash.toBuffer(), privateKey).toBuffer();
228
+ const authWitness = new AuthWitness(messageHash, [...signature]);
229
+ return this.txeDatabase.addAuthWitness(authWitness.requestHash, authWitness.witness);
230
+ }
231
+
232
+ async addNullifiers(contractAddress: AztecAddress, nullifiers: Fr[]) {
233
+ const db = this.trees.asLatest();
234
+ const siloedNullifiers = nullifiers.map(nullifier => siloNullifier(contractAddress, nullifier).toBuffer());
235
+
236
+ await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, siloedNullifiers, NULLIFIER_SUBTREE_HEIGHT);
237
+ }
238
+
239
+ async addNoteHashes(contractAddress: AztecAddress, innerNoteHashes: Fr[]) {
240
+ const db = this.trees.asLatest();
241
+ const siloedNoteHashes = innerNoteHashes.map(innerNoteHash => siloNoteHash(contractAddress, innerNoteHash));
242
+ await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, siloedNoteHashes);
243
+ }
244
+
245
+ // TypedOracle
246
+
247
+ getBlockNumber() {
248
+ return Promise.resolve(this.blockNumber);
249
+ }
250
+
251
+ getContractAddress() {
252
+ return Promise.resolve(this.contractAddress);
253
+ }
254
+
255
+ getRandomField() {
256
+ return Fr.random();
257
+ }
258
+
259
+ packArgumentsArray(args: Fr[]) {
260
+ return Promise.resolve(this.packedValuesCache.pack(args));
261
+ }
262
+
263
+ packReturns(returns: Fr[]) {
264
+ return Promise.resolve(this.packedValuesCache.pack(returns));
265
+ }
266
+
267
+ unpackReturns(returnsHash: Fr) {
268
+ return Promise.resolve(this.packedValuesCache.unpack(returnsHash));
269
+ }
270
+
271
+ getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
272
+ return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
273
+ }
274
+
275
+ async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
276
+ const contractInstance = await this.contractDataOracle.getContractInstance(address);
277
+ if (!contractInstance) {
278
+ throw new Error(`Contract instance not found for address ${address}`);
279
+ }
280
+ return contractInstance;
281
+ }
282
+
283
+ getMembershipWitness(_blockNumber: number, _treeId: MerkleTreeId, _leafValue: Fr): Promise<Fr[] | undefined> {
284
+ throw new Error('Method not implemented.');
285
+ }
286
+
287
+ async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr) {
288
+ const committedDb = new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
289
+ const result = await committedDb.getSiblingPath(treeId, leafIndex.toBigInt());
290
+ return result.toFields();
291
+ }
292
+
293
+ async getNullifierMembershipWitness(
294
+ blockNumber: number,
295
+ nullifier: Fr,
296
+ ): Promise<NullifierMembershipWitness | undefined> {
297
+ const committedDb = new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
298
+ const index = await committedDb.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
299
+ if (!index) {
300
+ return undefined;
301
+ }
302
+
303
+ const leafPreimagePromise = committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
304
+ const siblingPathPromise = committedDb.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
305
+ MerkleTreeId.NULLIFIER_TREE,
306
+ BigInt(index),
307
+ );
308
+
309
+ const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
310
+
311
+ if (!leafPreimage) {
312
+ return undefined;
313
+ }
314
+
315
+ return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath);
316
+ }
317
+
318
+ async getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
319
+ const committedDb = new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
320
+ const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
321
+ if (!lowLeafResult) {
322
+ return undefined;
323
+ } else {
324
+ const preimage = (await committedDb.getLeafPreimage(
325
+ MerkleTreeId.PUBLIC_DATA_TREE,
326
+ lowLeafResult.index,
327
+ )) as PublicDataTreeLeafPreimage;
328
+ const path = await committedDb.getSiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>(
329
+ MerkleTreeId.PUBLIC_DATA_TREE,
330
+ lowLeafResult.index,
331
+ );
332
+ return new PublicDataWitness(lowLeafResult.index, preimage, path);
333
+ }
334
+ }
335
+
336
+ getLowNullifierMembershipWitness(
337
+ _blockNumber: number,
338
+ _nullifier: Fr,
339
+ ): Promise<NullifierMembershipWitness | undefined> {
340
+ throw new Error('Method not implemented.');
341
+ }
342
+
343
+ getHeader(_blockNumber: number): Promise<Header | undefined> {
344
+ throw new Error('Method not implemented.');
345
+ }
346
+
347
+ getCompleteAddress(account: AztecAddress) {
348
+ return Promise.resolve(this.txeDatabase.getAccount(account));
349
+ }
350
+
351
+ getAuthWitness(messageHash: Fr) {
352
+ return this.txeDatabase.getAuthWitness(messageHash);
353
+ }
354
+
355
+ popCapsule(): Promise<Fr[]> {
356
+ throw new Error('Method not implemented.');
357
+ }
358
+
359
+ getNotes(
360
+ storageSlot: Fr,
361
+ numSelects: number,
362
+ selectByIndexes: number[],
363
+ selectByOffsets: number[],
364
+ selectByLengths: number[],
365
+ selectValues: Fr[],
366
+ selectComparators: number[],
367
+ sortByIndexes: number[],
368
+ sortByOffsets: number[],
369
+ sortByLengths: number[],
370
+ sortOrder: number[],
371
+ limit: number,
372
+ offset: number,
373
+ _status: NoteStatus,
374
+ ) {
375
+ // Nullified pending notes are already removed from the list.
376
+ const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
377
+
378
+ const notes = pickNotes<NoteData>(pendingNotes, {
379
+ selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
380
+ selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
381
+ value: selectValues[i],
382
+ comparator: selectComparators[i],
383
+ })),
384
+ sorts: sortByIndexes.map((index, i) => ({
385
+ selector: { index, offset: sortByOffsets[i], length: sortByLengths[i] },
386
+ order: sortOrder[i],
387
+ })),
388
+ limit,
389
+ offset,
390
+ });
391
+
392
+ this.logger.debug(
393
+ `Returning ${notes.length} notes for ${this.contractAddress} at ${storageSlot}: ${notes
394
+ .map(n => `${n.nonce.toString()}:[${n.note.items.map(i => i.toString()).join(',')}]`)
395
+ .join(', ')}`,
396
+ );
397
+
398
+ return Promise.resolve(notes);
399
+ }
400
+
401
+ notifyCreatedNote(storageSlot: Fr, noteTypeId: NoteSelector, noteItems: Fr[], innerNoteHash: Fr, counter: number) {
402
+ const note = new Note(noteItems);
403
+ this.noteCache.addNewNote(
404
+ {
405
+ contractAddress: this.contractAddress,
406
+ storageSlot,
407
+ nonce: Fr.ZERO, // Nonce cannot be known during private execution.
408
+ note,
409
+ siloedNullifier: undefined, // Siloed nullifier cannot be known for newly created note.
410
+ innerNoteHash,
411
+ },
412
+ counter,
413
+ );
414
+ return Promise.resolve();
415
+ }
416
+
417
+ notifyNullifiedNote(innerNullifier: Fr, innerNoteHash: Fr, _counter: number) {
418
+ this.noteCache.nullifyNote(this.contractAddress, innerNullifier, innerNoteHash);
419
+ return Promise.resolve();
420
+ }
421
+
422
+ async checkNullifierExists(innerNullifier: Fr): Promise<boolean> {
423
+ const nullifier = siloNullifier(this.contractAddress, innerNullifier!);
424
+ const db = this.trees.asLatest();
425
+ const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
426
+ return index !== undefined;
427
+ }
428
+
429
+ getL1ToL2MembershipWitness(
430
+ _contractAddress: AztecAddress,
431
+ _messageHash: Fr,
432
+ _secret: Fr,
433
+ ): Promise<MessageLoadOracleInputs<16>> {
434
+ throw new Error('Method not implemented.');
435
+ }
436
+
437
+ async storageRead(startStorageSlot: Fr, numberOfElements: number): Promise<Fr[]> {
438
+ const db = this.trees.asLatest();
439
+
440
+ const values = [];
441
+ for (let i = 0n; i < numberOfElements; i++) {
442
+ const storageSlot = startStorageSlot.add(new Fr(i));
443
+ const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, storageSlot).toBigInt();
444
+
445
+ const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
446
+
447
+ let value = Fr.ZERO;
448
+ if (lowLeafResult && lowLeafResult.alreadyPresent) {
449
+ const preimage = (await db.getLeafPreimage(
450
+ MerkleTreeId.PUBLIC_DATA_TREE,
451
+ lowLeafResult.index,
452
+ )) as PublicDataTreeLeafPreimage;
453
+ value = preimage.value;
454
+ }
455
+ this.logger.debug(`Oracle storage read: slot=${storageSlot.toString()} value=${value}`);
456
+ values.push(value);
457
+ }
458
+ return values;
459
+ }
460
+
461
+ async storageWrite(startStorageSlot: Fr, values: Fr[]): Promise<Fr[]> {
462
+ const db = this.trees.asLatest();
463
+
464
+ const publicDataWrites = values.map((value, i) => {
465
+ const storageSlot = startStorageSlot.add(new Fr(i));
466
+ this.logger.debug(`Oracle storage write: slot=${storageSlot.toString()} value=${value}`);
467
+ return new PublicDataWrite(computePublicDataTreeLeafSlot(this.contractAddress, storageSlot), value);
468
+ });
469
+ await db.batchInsert(
470
+ MerkleTreeId.PUBLIC_DATA_TREE,
471
+ publicDataWrites.map(write => new PublicDataTreeLeaf(write.leafIndex, write.newValue).toBuffer()),
472
+ PUBLIC_DATA_SUBTREE_HEIGHT,
473
+ );
474
+ return publicDataWrites.map(write => write.newValue);
475
+ }
476
+
477
+ emitEncryptedLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedNote: Buffer, _counter: number): void {
478
+ return;
479
+ }
480
+
481
+ emitEncryptedNoteLog(_noteHashCounter: number, _encryptedNote: Buffer, _counter: number): void {
482
+ return;
483
+ }
484
+
485
+ computeEncryptedNoteLog(
486
+ contractAddress: AztecAddress,
487
+ storageSlot: Fr,
488
+ noteTypeId: NoteSelector,
489
+ ovKeys: KeyValidationRequest,
490
+ ivpkM: Point,
491
+ preimage: Fr[],
492
+ ): Buffer {
493
+ const note = new Note(preimage);
494
+ const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
495
+ const taggedNote = new TaggedLog(l1NotePayload);
496
+
497
+ const ephSk = GrumpkinScalar.random();
498
+
499
+ const recipient = AztecAddress.random();
500
+
501
+ return taggedNote.encrypt(ephSk, recipient, ivpkM, ovKeys);
502
+ }
503
+
504
+ emitUnencryptedLog(_log: UnencryptedL2Log, _counter: number): void {
505
+ return;
506
+ }
507
+
508
+ emitContractClassUnencryptedLog(_log: UnencryptedL2Log, _counter: number): Fr {
509
+ throw new Error('Method not implemented.');
510
+ }
511
+
512
+ async callPrivateFunction(
513
+ targetContractAddress: AztecAddress,
514
+ functionSelector: FunctionSelector,
515
+ argsHash: Fr,
516
+ sideEffectCounter: number,
517
+ isStaticCall: boolean,
518
+ isDelegateCall: boolean,
519
+ ): Promise<PrivateCallStackItem> {
520
+ this.logger.verbose(
521
+ `Executing external function ${targetContractAddress}:${functionSelector}(${await this.getDebugFunctionName(
522
+ targetContractAddress,
523
+ functionSelector,
524
+ )}) isStaticCall=${isStaticCall} isDelegateCall=${isDelegateCall}`,
525
+ );
526
+
527
+ // Store and modify env
528
+ const currentContractAddress = AztecAddress.fromField(this.contractAddress);
529
+ const currentMessageSender = AztecAddress.fromField(this.msgSender);
530
+ const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
531
+ this.setMsgSender(this.contractAddress);
532
+ this.setContractAddress(targetContractAddress);
533
+ this.setFunctionSelector(functionSelector);
534
+
535
+ const artifact = await this.contractDataOracle.getFunctionArtifact(targetContractAddress, functionSelector);
536
+
537
+ const acir = artifact.bytecode;
538
+ const initialWitness = await this.getInitialWitness(
539
+ artifact,
540
+ argsHash,
541
+ sideEffectCounter,
542
+ isStaticCall,
543
+ isDelegateCall,
544
+ );
545
+ const acvmCallback = new Oracle(this);
546
+ const timer = new Timer();
547
+ try {
548
+ const acirExecutionResult = await acvm(acir, initialWitness, acvmCallback).catch((err: Error) => {
549
+ const execError = new ExecutionError(
550
+ err.message,
551
+ {
552
+ contractAddress: targetContractAddress,
553
+ functionSelector,
554
+ },
555
+ extractCallStack(err, artifact.debug),
556
+ { cause: err },
557
+ );
558
+ this.logger.debug(`Error executing private function ${targetContractAddress}:${functionSelector}`);
559
+ throw createSimulationError(execError);
560
+ });
561
+ const duration = timer.ms();
562
+ const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
563
+ const publicInputs = PrivateCircuitPublicInputs.fromFields(returnWitness);
564
+
565
+ const initialWitnessSize = witnessMapToFields(initialWitness).length * Fr.SIZE_IN_BYTES;
566
+ this.logger.debug(`Ran external function ${targetContractAddress.toString()}:${functionSelector}`, {
567
+ circuitName: 'app-circuit',
568
+ duration,
569
+ eventName: 'circuit-witness-generation',
570
+ inputSize: initialWitnessSize,
571
+ outputSize: publicInputs.toBuffer().length,
572
+ appCircuitName: 'noname',
573
+ } satisfies CircuitWitnessGenerationStats);
574
+
575
+ const callStackItem = new PrivateCallStackItem(
576
+ targetContractAddress,
577
+ new FunctionData(functionSelector, true),
578
+ publicInputs,
579
+ );
580
+ // Apply side effects
581
+ this.sideEffectsCounter = publicInputs.endSideEffectCounter.toNumber();
582
+
583
+ await this.addNullifiers(
584
+ targetContractAddress,
585
+ publicInputs.newNullifiers.filter(nullifier => !nullifier.isEmpty()).map(nullifier => nullifier.value),
586
+ );
587
+
588
+ await this.addNoteHashes(
589
+ targetContractAddress,
590
+ publicInputs.newNoteHashes.filter(noteHash => !noteHash.isEmpty()).map(noteHash => noteHash.value),
591
+ );
592
+
593
+ return callStackItem;
594
+ } finally {
595
+ this.setContractAddress(currentContractAddress);
596
+ this.setMsgSender(currentMessageSender);
597
+ this.setFunctionSelector(currentFunctionSelector);
598
+ }
599
+ }
600
+
601
+ async getInitialWitness(
602
+ abi: FunctionAbi,
603
+ argsHash: Fr,
604
+ sideEffectCounter: number,
605
+ isStaticCall: boolean,
606
+ isDelegateCall: boolean,
607
+ ) {
608
+ const argumentsSize = countArgumentsSize(abi);
609
+
610
+ const args = this.packedValuesCache.unpack(argsHash);
611
+
612
+ if (args.length !== argumentsSize) {
613
+ throw new Error('Invalid arguments size');
614
+ }
615
+
616
+ const privateContextInputs = await this.getPrivateContextInputs(
617
+ this.blockNumber - 1,
618
+ sideEffectCounter,
619
+ isStaticCall,
620
+ isDelegateCall,
621
+ );
622
+
623
+ const fields = [...privateContextInputs.toFields(), ...args];
624
+
625
+ return toACVMWitness(0, fields);
626
+ }
627
+
628
+ public async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
629
+ const instance = await this.contractDataOracle.getContractInstance(address);
630
+ if (!instance) {
631
+ return undefined;
632
+ }
633
+ const artifact = await this.contractDataOracle.getContractArtifact(instance!.contractClassId);
634
+ if (!artifact) {
635
+ return undefined;
636
+ }
637
+
638
+ const f = artifact.functions.find(f =>
639
+ FunctionSelector.fromNameAndParameters(f.name, f.parameters).equals(selector),
640
+ );
641
+ if (!f) {
642
+ return undefined;
643
+ }
644
+
645
+ return `${artifact.name}:${f.name}`;
646
+ }
647
+
648
+ async executePublicFunction(
649
+ targetContractAddress: AztecAddress,
650
+ functionSelector: FunctionSelector,
651
+ args: Fr[],
652
+ callContext: CallContext,
653
+ ) {
654
+ const header = Header.empty();
655
+ header.state = await this.trees.getStateReference(true);
656
+ header.globalVariables.blockNumber = new Fr(await this.getBlockNumber());
657
+ header.state.partial.nullifierTree.root = Fr.fromBuffer(
658
+ (await this.trees.getTreeInfo(MerkleTreeId.NULLIFIER_TREE, true)).root,
659
+ );
660
+ header.state.partial.noteHashTree.root = Fr.fromBuffer(
661
+ (await this.trees.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE, true)).root,
662
+ );
663
+ header.state.partial.publicDataTree.root = Fr.fromBuffer(
664
+ (await this.trees.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE, true)).root,
665
+ );
666
+ header.state.l1ToL2MessageTree.root = Fr.fromBuffer(
667
+ (await this.trees.getTreeInfo(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, true)).root,
668
+ );
669
+ const executor = new PublicExecutor(
670
+ new TXEPublicStateDB(this),
671
+ new ContractsDataSourcePublicDB(new TXEPublicContractDataSource(this)),
672
+ new WorldStateDB(this.trees.asLatest()),
673
+ header,
674
+ );
675
+ const execution = {
676
+ contractAddress: targetContractAddress,
677
+ functionSelector,
678
+ args,
679
+ callContext,
680
+ };
681
+
682
+ return executor.simulate(
683
+ execution,
684
+ GlobalVariables.empty(),
685
+ Gas.test(),
686
+ TxContext.empty(),
687
+ /* pendingNullifiers */ [],
688
+ /* transactionFee */ Fr.ZERO,
689
+ callContext.sideEffectCounter,
690
+ );
691
+ }
692
+
693
+ async avmOpcodeCall(
694
+ targetContractAddress: AztecAddress,
695
+ functionSelector: FunctionSelector,
696
+ args: Fr[],
697
+ isStaticCall: boolean,
698
+ isDelegateCall: boolean,
699
+ ) {
700
+ // Store and modify env
701
+ const currentContractAddress = AztecAddress.fromField(this.contractAddress);
702
+ const currentMessageSender = AztecAddress.fromField(this.msgSender);
703
+ const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
704
+ this.setMsgSender(this.contractAddress);
705
+ this.setContractAddress(targetContractAddress);
706
+ this.setFunctionSelector(functionSelector);
707
+
708
+ const callContext = CallContext.empty();
709
+ callContext.msgSender = this.msgSender;
710
+ callContext.functionSelector = this.functionSelector;
711
+ callContext.sideEffectCounter = this.sideEffectsCounter;
712
+ callContext.storageContractAddress = targetContractAddress;
713
+ callContext.isStaticCall = isStaticCall;
714
+ callContext.isDelegateCall = isDelegateCall;
715
+
716
+ const executionResult = await this.executePublicFunction(
717
+ targetContractAddress,
718
+ functionSelector,
719
+ args,
720
+ callContext,
721
+ );
722
+
723
+ // Apply side effects
724
+ if (!executionResult.reverted) {
725
+ this.sideEffectsCounter += executionResult.endSideEffectCounter.toNumber();
726
+ }
727
+ this.setContractAddress(currentContractAddress);
728
+ this.setMsgSender(currentMessageSender);
729
+ this.setFunctionSelector(currentFunctionSelector);
730
+
731
+ return executionResult;
732
+ }
733
+
734
+ async callPublicFunction(
735
+ targetContractAddress: AztecAddress,
736
+ functionSelector: FunctionSelector,
737
+ argsHash: Fr,
738
+ sideEffectCounter: number,
739
+ isStaticCall: boolean,
740
+ isDelegateCall: boolean,
741
+ ): Promise<Fr[]> {
742
+ // Store and modify env
743
+ const currentContractAddress = AztecAddress.fromField(this.contractAddress);
744
+ const currentMessageSender = AztecAddress.fromField(this.msgSender);
745
+ const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
746
+ this.setMsgSender(this.contractAddress);
747
+ this.setContractAddress(targetContractAddress);
748
+ this.setFunctionSelector(functionSelector);
749
+
750
+ const callContext = CallContext.empty();
751
+ callContext.msgSender = this.msgSender;
752
+ callContext.functionSelector = this.functionSelector;
753
+ callContext.sideEffectCounter = sideEffectCounter;
754
+ callContext.storageContractAddress = targetContractAddress;
755
+ callContext.isStaticCall = isStaticCall;
756
+ callContext.isDelegateCall = isDelegateCall;
757
+
758
+ const args = this.packedValuesCache.unpack(argsHash);
759
+
760
+ const executionResult = await this.executePublicFunction(
761
+ targetContractAddress,
762
+ functionSelector,
763
+ args,
764
+ callContext,
765
+ );
766
+
767
+ // Apply side effects
768
+ this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber();
769
+ this.setContractAddress(currentContractAddress);
770
+ this.setMsgSender(currentMessageSender);
771
+ this.setFunctionSelector(currentFunctionSelector);
772
+
773
+ return executionResult.returnValues;
774
+ }
775
+
776
+ async enqueuePublicFunctionCall(
777
+ targetContractAddress: AztecAddress,
778
+ functionSelector: FunctionSelector,
779
+ argsHash: Fr,
780
+ sideEffectCounter: number,
781
+ isStaticCall: boolean,
782
+ isDelegateCall: boolean,
783
+ ): Promise<PublicCallRequest> {
784
+ // Store and modify env
785
+ const currentContractAddress = AztecAddress.fromField(this.contractAddress);
786
+ const currentMessageSender = AztecAddress.fromField(this.msgSender);
787
+ const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
788
+ this.setMsgSender(this.contractAddress);
789
+ this.setContractAddress(targetContractAddress);
790
+ this.setFunctionSelector(functionSelector);
791
+
792
+ const callContext = CallContext.empty();
793
+ callContext.msgSender = this.msgSender;
794
+ callContext.functionSelector = this.functionSelector;
795
+ callContext.sideEffectCounter = sideEffectCounter;
796
+ callContext.storageContractAddress = targetContractAddress;
797
+ callContext.isStaticCall = isStaticCall;
798
+ callContext.isDelegateCall = isDelegateCall;
799
+
800
+ const args = this.packedValuesCache.unpack(argsHash);
801
+
802
+ const executionResult = await this.executePublicFunction(
803
+ targetContractAddress,
804
+ functionSelector,
805
+ args,
806
+ callContext,
807
+ );
808
+
809
+ // Apply side effects
810
+ this.sideEffectsCounter += executionResult.endSideEffectCounter.toNumber();
811
+ this.setContractAddress(currentContractAddress);
812
+ this.setMsgSender(currentMessageSender);
813
+ this.setFunctionSelector(currentFunctionSelector);
814
+
815
+ const parentCallContext = CallContext.empty();
816
+ parentCallContext.msgSender = currentMessageSender;
817
+ parentCallContext.functionSelector = currentFunctionSelector;
818
+ parentCallContext.sideEffectCounter = sideEffectCounter;
819
+ parentCallContext.storageContractAddress = currentContractAddress;
820
+ parentCallContext.isStaticCall = isStaticCall;
821
+ parentCallContext.isDelegateCall = isDelegateCall;
822
+
823
+ return PublicCallRequest.from({
824
+ parentCallContext,
825
+ contractAddress: targetContractAddress,
826
+ functionSelector,
827
+ callContext,
828
+ args,
829
+ });
830
+ }
831
+
832
+ setPublicTeardownFunctionCall(
833
+ _targetContractAddress: AztecAddress,
834
+ _functionSelector: FunctionSelector,
835
+ _argsHash: Fr,
836
+ _sideEffectCounter: number,
837
+ _isStaticCall: boolean,
838
+ _isDelegateCall: boolean,
839
+ ): Promise<PublicCallRequest> {
840
+ throw new Error('Method not implemented.');
841
+ }
842
+
843
+ aes128Encrypt(input: Buffer, initializationVector: Buffer, key: Buffer): Buffer {
844
+ const aes128 = new Aes128();
845
+ return aes128.encryptBufferCBC(input, initializationVector, key);
846
+ }
847
+
848
+ debugLog(message: string, fields: Fr[]): void {
849
+ this.logger.verbose(`debug_log ${applyStringFormatting(message, fields)}`);
850
+ }
851
+
852
+ emitEncryptedEventLog(
853
+ _contractAddress: AztecAddress,
854
+ _randomness: Fr,
855
+ _encryptedEvent: Buffer,
856
+ _counter: number,
857
+ ): void {
858
+ return;
859
+ }
860
+
861
+ computeEncryptedEventLog(
862
+ _contractAddress: AztecAddress,
863
+ _randomness: Fr,
864
+ _eventTypeId: Fr,
865
+ _ovKeys: KeyValidationRequest,
866
+ _ivpkM: Point,
867
+ _preimage: Fr[],
868
+ ): Buffer {
869
+ throw new Error('Method not implemented.');
870
+ }
871
+ }