@aztec/txe 1.2.1 → 2.0.0-nightly.20250813

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.
@@ -3,22 +3,18 @@ import {
3
3
  DEFAULT_GAS_LIMIT,
4
4
  DEFAULT_TEARDOWN_GAS_LIMIT,
5
5
  type L1_TO_L2_MSG_TREE_HEIGHT,
6
- MAX_CONTRACT_CLASS_LOGS_PER_TX,
7
- MAX_ENQUEUED_CALLS_PER_TX,
8
6
  MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
9
- MAX_L2_TO_L1_MSGS_PER_TX,
10
7
  MAX_NOTE_HASHES_PER_TX,
11
8
  MAX_NULLIFIERS_PER_TX,
12
- MAX_PRIVATE_LOGS_PER_TX,
13
9
  NULLIFIER_SUBTREE_HEIGHT,
14
10
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
15
11
  PRIVATE_CONTEXT_INPUTS_LENGTH,
16
12
  } from '@aztec/constants';
17
13
  import { padArrayEnd } from '@aztec/foundation/collection';
18
- import { Aes128, Schnorr, poseidon2Hash } from '@aztec/foundation/crypto';
14
+ import { Aes128, Schnorr } from '@aztec/foundation/crypto';
19
15
  import { Fr, Point } from '@aztec/foundation/fields';
20
16
  import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
21
- import { TestDateProvider, Timer } from '@aztec/foundation/timer';
17
+ import { TestDateProvider } from '@aztec/foundation/timer';
22
18
  import { KeyStore } from '@aztec/key-store';
23
19
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
24
20
  import type { ProtocolContract } from '@aztec/protocol-contracts';
@@ -39,21 +35,17 @@ import {
39
35
  type NoteData,
40
36
  Oracle,
41
37
  PrivateExecutionOracle,
42
- type TypedOracle,
43
38
  UtilityExecutionOracle,
44
39
  executePrivateFunction,
45
- extractPrivateCircuitPublicInputs,
46
40
  generateSimulatedProvingResult,
47
41
  pickNotes,
48
42
  } from '@aztec/pxe/simulator';
49
43
  import { WASMSimulator, extractCallStack, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
50
- import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
51
44
  import {
52
45
  ExecutionError,
53
46
  GuardedMerkleTreeOperations,
54
47
  PublicContractsDB,
55
48
  PublicProcessor,
56
- type PublicTxResult,
57
49
  PublicTxSimulator,
58
50
  createSimulationError,
59
51
  resolveAssertionMessageFromError,
@@ -70,7 +62,6 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
70
62
  import { PublicDataWrite } from '@aztec/stdlib/avm';
71
63
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
72
64
  import type { ContractInstance, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
73
- import { SimulationError } from '@aztec/stdlib/errors';
74
65
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
75
66
  import {
76
67
  computeCalldataHash,
@@ -89,15 +80,10 @@ import {
89
80
  PrivateKernelTailCircuitPublicInputs,
90
81
  PrivateToPublicAccumulatedData,
91
82
  PublicCallRequest,
92
- RollupValidationRequests,
93
- ScopedLogHash,
94
83
  } from '@aztec/stdlib/kernel';
95
- import { deriveKeys } from '@aztec/stdlib/keys';
96
84
  import { ContractClassLog, IndexedTaggingSecret, PrivateLog, type PublicLog } from '@aztec/stdlib/logs';
97
- import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
98
85
  import type { NoteStatus } from '@aztec/stdlib/note';
99
86
  import { ClientIvcProof } from '@aztec/stdlib/proofs';
100
- import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats';
101
87
  import {
102
88
  makeAppendOnlyTreeSnapshot,
103
89
  makeContentCommitment,
@@ -107,7 +93,6 @@ import {
107
93
  import {
108
94
  AppendOnlyTreeSnapshot,
109
95
  MerkleTreeId,
110
- type NullifierLeafPreimage,
111
96
  NullifierMembershipWitness,
112
97
  PublicDataTreeLeaf,
113
98
  type PublicDataTreeLeafPreimage,
@@ -116,11 +101,9 @@ import {
116
101
  import {
117
102
  BlockHeader,
118
103
  CallContext,
119
- GlobalVariables,
120
104
  HashedValues,
121
105
  PrivateCallExecutionResult,
122
106
  PrivateExecutionResult,
123
- PublicCallRequestWithCalldata,
124
107
  Tx,
125
108
  TxConstantData,
126
109
  TxContext,
@@ -132,22 +115,18 @@ import type { UInt64 } from '@aztec/stdlib/types';
132
115
  import { ForkCheckpoint, NativeWorldStateService } from '@aztec/world-state/native';
133
116
 
134
117
  import { TXEStateMachine } from '../state_machine/index.js';
135
- import { AZTEC_SLOT_DURATION, GENESIS_TIMESTAMP } from '../txe_constants.js';
118
+ import { GENESIS_TIMESTAMP } from '../txe_constants.js';
136
119
  import { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
137
120
  import { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
138
121
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
139
122
 
140
- export class TXE implements TypedOracle {
123
+ export class TXE {
141
124
  private blockNumber = 1;
142
125
  private timestamp = GENESIS_TIMESTAMP;
143
126
 
144
127
  private sideEffectCounter = 0;
145
128
  private msgSender: AztecAddress;
146
129
  private functionSelector = FunctionSelector.fromField(new Fr(0));
147
- private isStaticCall = false;
148
- // Return/revert data of the latest nested call.
149
- private nestedCallReturndata: Fr[] = [];
150
- private nestedCallSuccess: boolean = false;
151
130
 
152
131
  private pxeOracleInterface: PXEOracleInterface;
153
132
 
@@ -170,6 +149,9 @@ export class TXE implements TypedOracle {
170
149
 
171
150
  private authwits: Map<string, AuthWitness> = new Map();
172
151
 
152
+ // Used by privateSetSenderForTags and privateGetSenderForTags oracles.
153
+ private senderForTags?: AztecAddress;
154
+
173
155
  private constructor(
174
156
  private logger: Logger,
175
157
  private keyStore: KeyStore,
@@ -261,11 +243,11 @@ export class TXE implements TypedOracle {
261
243
  return this.baseFork;
262
244
  }
263
245
 
264
- getChainId(): Promise<Fr> {
246
+ utilityGetChainId(): Promise<Fr> {
265
247
  return Promise.resolve(new Fr(this.CHAIN_ID));
266
248
  }
267
249
 
268
- getVersion(): Promise<Fr> {
250
+ utilityGetVersion(): Promise<Fr> {
269
251
  return Promise.resolve(new Fr(this.ROLLUP_VERSION));
270
252
  }
271
253
 
@@ -273,27 +255,7 @@ export class TXE implements TypedOracle {
273
255
  return this.msgSender;
274
256
  }
275
257
 
276
- getFunctionSelector() {
277
- return this.functionSelector;
278
- }
279
-
280
- setMsgSender(msgSender: AztecAddress) {
281
- this.msgSender = msgSender;
282
- }
283
-
284
- setFunctionSelector(functionSelector: FunctionSelector) {
285
- this.functionSelector = functionSelector;
286
- }
287
-
288
- getSideEffectsCounter() {
289
- return this.sideEffectCounter;
290
- }
291
-
292
- setSideEffectsCounter(sideEffectsCounter: number) {
293
- this.sideEffectCounter = sideEffectsCounter;
294
- }
295
-
296
- setContractAddress(contractAddress: AztecAddress) {
258
+ txeSetContractAddress(contractAddress: AztecAddress) {
297
259
  this.contractAddress = contractAddress;
298
260
  }
299
261
 
@@ -302,7 +264,7 @@ export class TXE implements TypedOracle {
302
264
  this.blockNumber = blockNumber;
303
265
  }
304
266
 
305
- advanceTimestampBy(duration: UInt64) {
267
+ txeAdvanceTimestampBy(duration: UInt64) {
306
268
  this.timestamp = this.timestamp + duration;
307
269
  }
308
270
 
@@ -330,16 +292,14 @@ export class TXE implements TypedOracle {
330
292
  await this.contractDataProvider.addContractArtifact(contractClassId, artifact);
331
293
  }
332
294
 
333
- async getPrivateContextInputs(
295
+ async txeGetPrivateContextInputs(
334
296
  blockNumber: number | null,
335
- timestamp: UInt64 | null,
336
297
  sideEffectsCounter = this.sideEffectCounter,
337
298
  isStaticCall = false,
338
299
  ) {
339
300
  // If blockNumber or timestamp is null, use the values corresponding to the latest historical block (number of
340
301
  // the block being built - 1)
341
302
  blockNumber = blockNumber ?? this.blockNumber - 1;
342
- timestamp = timestamp ?? this.timestamp - AZTEC_SLOT_DURATION;
343
303
 
344
304
  const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
345
305
  const previousBlockState = this.nativeWorldStateService.getSnapshot(blockNumber - 1);
@@ -349,7 +309,7 @@ export class TXE implements TypedOracle {
349
309
  inputs.txContext.chainId = new Fr(this.CHAIN_ID);
350
310
  inputs.txContext.version = new Fr(this.ROLLUP_VERSION);
351
311
  inputs.historicalHeader.globalVariables.blockNumber = blockNumber;
352
- inputs.historicalHeader.globalVariables.timestamp = timestamp;
312
+ inputs.historicalHeader.globalVariables.timestamp = await this.getBlockTimestamp(blockNumber);
353
313
  inputs.historicalHeader.state = stateReference;
354
314
  inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
355
315
  (await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
@@ -359,11 +319,7 @@ export class TXE implements TypedOracle {
359
319
  return inputs;
360
320
  }
361
321
 
362
- deriveKeys(secret: Fr) {
363
- return deriveKeys(secret);
364
- }
365
-
366
- async addAuthWitness(address: AztecAddress, messageHash: Fr) {
322
+ async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
367
323
  const account = await this.accountDataProvider.getAccount(address);
368
324
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
369
325
  const schnorr = new Schnorr();
@@ -401,57 +357,33 @@ export class TXE implements TypedOracle {
401
357
  this.uniqueNoteHashesFromPublic.push(...siloedNoteHashes);
402
358
  }
403
359
 
404
- async addPrivateLogs(contractAddress: AztecAddress, privateLogs: PrivateLog[]) {
405
- for (const privateLog of privateLogs) {
406
- privateLog.fields[0] = await poseidon2Hash([contractAddress, privateLog.fields[0]]);
407
- }
408
-
409
- this.privateLogs.push(...privateLogs);
410
- }
411
-
412
- addPublicLogs(logs: PublicLog[]) {
413
- logs.forEach(log => {
414
- try {
415
- const tag = log.fields[0];
416
- this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
417
- this.publicLogs.push(log);
418
- } catch (err) {
419
- this.logger.warn(`Failed to add tagged log to store: ${err}`);
420
- }
421
- });
422
- }
423
-
424
360
  // TypedOracle
425
361
 
426
- getBlockNumber() {
362
+ utilityGetBlockNumber() {
427
363
  return Promise.resolve(this.blockNumber);
428
364
  }
429
365
 
430
- getTimestamp() {
366
+ utilityGetTimestamp() {
431
367
  return Promise.resolve(this.timestamp);
432
368
  }
433
369
 
434
- getContractAddress() {
435
- return Promise.resolve(this.contractAddress);
436
- }
437
-
438
- setIsStaticCall(isStatic: boolean) {
439
- this.isStaticCall = isStatic;
370
+ txeGetLastBlockTimestamp() {
371
+ return this.getBlockTimestamp(this.blockNumber - 1);
440
372
  }
441
373
 
442
- getIsStaticCall() {
443
- return this.isStaticCall;
374
+ utilityGetContractAddress() {
375
+ return Promise.resolve(this.contractAddress);
444
376
  }
445
377
 
446
- getRandomField() {
378
+ utilityGetRandomField() {
447
379
  return Fr.random();
448
380
  }
449
381
 
450
- storeInExecutionCache(values: Fr[], hash: Fr) {
382
+ privateStoreInExecutionCache(values: Fr[], hash: Fr) {
451
383
  return this.executionCache.store(values, hash);
452
384
  }
453
385
 
454
- loadFromExecutionCache(hash: Fr) {
386
+ privateLoadFromExecutionCache(hash: Fr) {
455
387
  const preimage = this.executionCache.getPreimage(hash);
456
388
  if (!preimage) {
457
389
  throw new Error(`Preimage for hash ${hash.toString()} not found in cache`);
@@ -459,109 +391,50 @@ export class TXE implements TypedOracle {
459
391
  return Promise.resolve(preimage);
460
392
  }
461
393
 
462
- getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
394
+ utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
463
395
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
464
396
  }
465
397
 
466
- async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
467
- const contractInstance = await this.contractDataProvider.getContractInstance(address);
468
- if (!contractInstance) {
469
- throw new Error(`Contract instance not found for address ${address}`);
470
- }
471
- return contractInstance;
472
- }
473
-
474
- async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
475
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
476
- const index = (await snap.findLeafIndices(treeId, [leafValue.toBuffer()]))[0];
477
- if (index === undefined) {
478
- throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
479
- }
480
- const siblingPath = await snap.getSiblingPath(treeId, index);
481
-
482
- return [new Fr(index), ...siblingPath.toFields()];
398
+ utilityGetContractInstance(address: AztecAddress): Promise<ContractInstance> {
399
+ return this.pxeOracleInterface.getContractInstance(address);
483
400
  }
484
401
 
485
- async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr) {
486
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
487
-
488
- const result = await snap.getSiblingPath(treeId, leafIndex.toBigInt());
489
- return result.toFields();
402
+ utilityGetMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
403
+ return this.pxeOracleInterface.getMembershipWitness(blockNumber, treeId, leafValue);
490
404
  }
491
405
 
492
- async getNullifierMembershipWitness(
406
+ utilityGetNullifierMembershipWitness(
493
407
  blockNumber: number,
494
408
  nullifier: Fr,
495
409
  ): Promise<NullifierMembershipWitness | undefined> {
496
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
497
-
498
- const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
499
- if (!index) {
500
- return undefined;
501
- }
502
-
503
- const leafPreimagePromise = snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
504
- const siblingPathPromise = snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
505
-
506
- const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
507
-
508
- if (!leafPreimage) {
509
- return undefined;
510
- }
511
-
512
- return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath);
410
+ return this.pxeOracleInterface.getNullifierMembershipWitness(blockNumber, nullifier);
513
411
  }
514
412
 
515
- async getPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
516
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
517
-
518
- const lowLeafResult = await snap.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
519
- if (!lowLeafResult) {
520
- return undefined;
521
- } else {
522
- const preimage = (await snap.getLeafPreimage(
523
- MerkleTreeId.PUBLIC_DATA_TREE,
524
- lowLeafResult.index,
525
- )) as PublicDataTreeLeafPreimage;
526
- const path = await snap.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
527
- return new PublicDataWitness(lowLeafResult.index, preimage, path);
528
- }
413
+ utilityGetPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
414
+ return this.pxeOracleInterface.getPublicDataWitness(blockNumber, leafSlot);
529
415
  }
530
416
 
531
- async getLowNullifierMembershipWitness(
417
+ utilityGetLowNullifierMembershipWitness(
532
418
  blockNumber: number,
533
419
  nullifier: Fr,
534
420
  ): Promise<NullifierMembershipWitness | undefined> {
535
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
536
-
537
- const findResult = await snap.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
538
- if (!findResult) {
539
- return undefined;
540
- }
541
- const { index, alreadyPresent } = findResult;
542
- if (alreadyPresent) {
543
- this.logger.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
544
- }
545
- const preimageData = (await snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!;
546
-
547
- const siblingPath = await snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
548
- return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath);
421
+ return this.pxeOracleInterface.getLowNullifierMembershipWitness(blockNumber, nullifier);
549
422
  }
550
423
 
551
- getBlockHeader(blockNumber: number): Promise<BlockHeader | undefined> {
424
+ utilityGetBlockHeader(blockNumber: number): Promise<BlockHeader | undefined> {
552
425
  return this.stateMachine.archiver.getBlockHeader(blockNumber);
553
426
  }
554
427
 
555
- getCompleteAddress(account: AztecAddress) {
428
+ utilityGetCompleteAddress(account: AztecAddress) {
556
429
  return Promise.resolve(this.accountDataProvider.getAccount(account));
557
430
  }
558
431
 
559
- getAuthWitness(messageHash: Fr) {
432
+ utilityGetAuthWitness(messageHash: Fr) {
560
433
  const authwit = this.authwits.get(messageHash.toString());
561
434
  return Promise.resolve(authwit?.witness);
562
435
  }
563
436
 
564
- async getNotes(
437
+ async utilityGetNotes(
565
438
  storageSlot: Fr,
566
439
  numSelects: number,
567
440
  selectByIndexes: number[],
@@ -607,7 +480,7 @@ export class TXE implements TypedOracle {
607
480
  return notes;
608
481
  }
609
482
 
610
- notifyCreatedNote(storageSlot: Fr, _noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
483
+ privateNotifyCreatedNote(storageSlot: Fr, _noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
611
484
  const note = new Note(noteItems);
612
485
  this.noteCache.addNewNote(
613
486
  {
@@ -623,23 +496,26 @@ export class TXE implements TypedOracle {
623
496
  this.sideEffectCounter = counter + 1;
624
497
  }
625
498
 
626
- async notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
499
+ async privateNotifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
627
500
  await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
628
501
  await this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
629
502
  this.sideEffectCounter = counter + 1;
630
503
  }
631
504
 
632
- async notifyCreatedNullifier(innerNullifier: Fr): Promise<void> {
505
+ async privateNotifyCreatedNullifier(innerNullifier: Fr): Promise<void> {
633
506
  await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
634
507
  await this.noteCache.nullifierCreated(this.contractAddress, innerNullifier);
635
508
  }
636
509
 
637
- async checkNullifierExists(innerNullifier: Fr): Promise<boolean> {
510
+ async utilityCheckNullifierExists(innerNullifier: Fr): Promise<boolean> {
638
511
  const snap = this.nativeWorldStateService.getSnapshot(this.blockNumber - 1);
639
512
 
640
513
  const nullifier = await siloNullifier(this.contractAddress, innerNullifier!);
641
514
  const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]);
642
- return index !== undefined;
515
+
516
+ const inPendingCache = this.noteCache.getNullifiers(this.contractAddress).has(nullifier.toBigInt());
517
+
518
+ return index !== undefined || inPendingCache;
643
519
  }
644
520
 
645
521
  getL1ToL2MembershipWitness(
@@ -650,7 +526,7 @@ export class TXE implements TypedOracle {
650
526
  throw new Error('Method not implemented.');
651
527
  }
652
528
 
653
- async storageRead(
529
+ async utilityStorageRead(
654
530
  contractAddress: AztecAddress,
655
531
  startStorageSlot: Fr,
656
532
  blockNumber: number,
@@ -698,7 +574,7 @@ export class TXE implements TypedOracle {
698
574
  }
699
575
 
700
576
  async commitState() {
701
- const blockNumber = await this.getBlockNumber();
577
+ const blockNumber = await this.utilityGetBlockNumber();
702
578
  const { usedTxRequestHashForNonces } = this.noteCache.finish();
703
579
  if (this.committedBlocks.has(blockNumber)) {
704
580
  throw new Error('Already committed state');
@@ -786,7 +662,11 @@ export class TXE implements TypedOracle {
786
662
  );
787
663
 
788
664
  header.globalVariables.blockNumber = blockNumber;
789
- header.globalVariables.timestamp = await this.getTimestamp();
665
+ header.globalVariables.timestamp = await this.utilityGetTimestamp();
666
+ header.globalVariables.version = new Fr(this.ROLLUP_VERSION);
667
+ header.globalVariables.chainId = new Fr(this.CHAIN_ID);
668
+
669
+ this.logger.info(`Created block ${blockNumber} with timestamp ${header.globalVariables.timestamp}`);
790
670
 
791
671
  l2Block.header = header;
792
672
 
@@ -837,7 +717,7 @@ export class TXE implements TypedOracle {
837
717
  selector: call.selector,
838
718
  });
839
719
 
840
- const args = await this.loadFromExecutionCache(argsHash);
720
+ const args = await this.privateLoadFromExecutionCache(argsHash);
841
721
  const initialWitness = toACVMWitness(0, args);
842
722
  const acirExecutionResult = await this.simulator
843
723
  .executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle).toACIRCallback())
@@ -859,89 +739,13 @@ export class TXE implements TypedOracle {
859
739
 
860
740
  const returnHash = await computeVarArgsHash(returnWitness);
861
741
 
862
- this.storeInExecutionCache(returnWitness, returnHash);
742
+ this.privateStoreInExecutionCache(returnWitness, returnHash);
863
743
  return returnHash;
864
744
  } catch (err) {
865
745
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
866
746
  }
867
747
  }
868
748
 
869
- async callPrivateFunction(
870
- targetContractAddress: AztecAddress,
871
- functionSelector: FunctionSelector,
872
- argsHash: Fr,
873
- sideEffectCounter: number,
874
- isStaticCall: boolean,
875
- ) {
876
- this.logger.verbose(
877
- `Executing external function ${await this.getDebugFunctionName(
878
- targetContractAddress,
879
- functionSelector,
880
- )}@${targetContractAddress} isStaticCall=${isStaticCall}`,
881
- );
882
-
883
- // Store and modify env
884
- const currentContractAddress = this.contractAddress;
885
- const currentMessageSender = this.msgSender;
886
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
887
- this.setMsgSender(this.contractAddress);
888
- this.setContractAddress(targetContractAddress);
889
- this.setFunctionSelector(functionSelector);
890
-
891
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
892
- if (!artifact) {
893
- throw new Error(`Artifact not found when calling private function. Contract address: ${targetContractAddress}.`);
894
- }
895
-
896
- const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
897
- const acvmCallback = new Oracle(this);
898
- const timer = new Timer();
899
- const acirExecutionResult = await this.simulator
900
- .executeUserCircuit(initialWitness, artifact, acvmCallback.toACIRCallback())
901
- .catch((err: Error) => {
902
- err.message = resolveAssertionMessageFromError(err, artifact);
903
-
904
- const execError = new ExecutionError(
905
- err.message,
906
- {
907
- contractAddress: targetContractAddress,
908
- functionSelector,
909
- },
910
- extractCallStack(err, artifact.debug),
911
- { cause: err },
912
- );
913
- this.logger.debug(`Error executing private function ${targetContractAddress}:${functionSelector}`);
914
- throw createSimulationError(execError);
915
- });
916
- const duration = timer.ms();
917
- const publicInputs = extractPrivateCircuitPublicInputs(artifact, acirExecutionResult.partialWitness);
918
-
919
- const initialWitnessSize = witnessMapToFields(initialWitness).length * Fr.SIZE_IN_BYTES;
920
- this.logger.debug(`Ran external function ${targetContractAddress.toString()}:${functionSelector}`, {
921
- circuitName: 'app-circuit',
922
- duration,
923
- eventName: 'circuit-witness-generation',
924
- inputSize: initialWitnessSize,
925
- outputSize: publicInputs.toBuffer().length,
926
- appCircuitName: 'noname',
927
- } satisfies CircuitWitnessGenerationStats);
928
-
929
- // Apply side effects
930
- const endSideEffectCounter = publicInputs.endSideEffectCounter;
931
- this.sideEffectCounter = endSideEffectCounter.toNumber() + 1;
932
-
933
- await this.addPrivateLogs(
934
- targetContractAddress,
935
- publicInputs.privateLogs.filter(privateLog => !privateLog.isEmpty()).map(privateLog => privateLog.log),
936
- );
937
-
938
- this.setContractAddress(currentContractAddress);
939
- this.setMsgSender(currentMessageSender);
940
- this.setFunctionSelector(currentFunctionSelector);
941
-
942
- return { endSideEffectCounter, returnsHash: publicInputs.returnsHash };
943
- }
944
-
945
749
  async getInitialWitness(abi: FunctionAbi, argsHash: Fr, sideEffectCounter: number, isStaticCall: boolean) {
946
750
  const argumentsSize = countArgumentsSize(abi);
947
751
 
@@ -951,9 +755,10 @@ export class TXE implements TypedOracle {
951
755
  throw new Error('Invalid arguments size');
952
756
  }
953
757
 
954
- const privateContextInputs = await this.getPrivateContextInputs(
955
- this.blockNumber - 1,
956
- this.timestamp - AZTEC_SLOT_DURATION,
758
+ const historicalBlockNumber = this.blockNumber - 1; // i.e. last
759
+
760
+ const privateContextInputs = await this.txeGetPrivateContextInputs(
761
+ historicalBlockNumber,
957
762
  sideEffectCounter,
958
763
  isStaticCall,
959
764
  );
@@ -970,179 +775,22 @@ export class TXE implements TypedOracle {
970
775
  return await this.contractDataProvider.getDebugFunctionName(address, selector);
971
776
  }
972
777
 
973
- private async executePublicFunction(
974
- calldata: Fr[],
975
- msgSender: AztecAddress,
976
- contractAddress: AztecAddress,
977
- isStaticCall: boolean,
978
- isTeardown: boolean = false,
979
- ) {
980
- const callRequest = await PublicCallRequest.fromCalldata(msgSender, contractAddress, isStaticCall, calldata);
981
- const executionRequest = new PublicCallRequestWithCalldata(callRequest, calldata);
982
-
983
- const db = this.baseFork;
984
-
985
- const globalVariables = GlobalVariables.empty();
986
- globalVariables.chainId = new Fr(this.CHAIN_ID);
987
- globalVariables.version = new Fr(this.ROLLUP_VERSION);
988
- globalVariables.blockNumber = this.blockNumber;
989
- globalVariables.timestamp = this.timestamp;
990
- globalVariables.gasFees = new GasFees(1, 1);
991
-
992
- let result: PublicTxResult;
993
- // Checkpoint here so that we can revert merkle ops after simulation.
994
- // See note at revert below.
995
- const checkpoint = await ForkCheckpoint.new(db);
996
- try {
997
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
998
- const simulator = new PublicTxSimulator(
999
- this.baseFork,
1000
- contractsDB,
1001
- globalVariables,
1002
- /*doMerkleOperations=*/ false,
1003
- /*skipFeeEnforcement=*/ false,
1004
- /*clientInitiatedSimulation=*/ true,
1005
- );
1006
-
1007
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
1008
- const firstNullifier = usedTxRequestHashForNonces
1009
- ? this.getTxRequestHash()
1010
- : this.noteCache.getAllNullifiers()[0];
1011
-
1012
- // When setting up a teardown call, we tell it that
1013
- // private execution used Gas(1, 1) so it can compute a tx fee.
1014
- const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty();
1015
- const tx = createTxForPublicCalls(
1016
- {
1017
- nonRevertible: {
1018
- nullifiers: [firstNullifier],
1019
- },
1020
- },
1021
- /*setupExecutionRequests=*/ [],
1022
- /*appExecutionRequests=*/ isTeardown ? [] : [executionRequest],
1023
- /*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined,
1024
- /*feePayer=*/ AztecAddress.zero(),
1025
- gasUsedByPrivate,
1026
- );
1027
-
1028
- result = await simulator.simulate(tx);
1029
- } finally {
1030
- // NOTE: Don't accept any merkle updates from the AVM since this was just 1 enqueued call
1031
- // and the TXE will re-apply all txEffects after entire execution (all enqueued calls)
1032
- // complete.
1033
- await checkpoint.revert();
1034
- // If an error is thrown during the above simulation, this revert is the last
1035
- // thing executed and we skip the postprocessing below.
1036
- }
1037
-
1038
- const noteHashes = result.avmProvingRequest.inputs.publicInputs.accumulatedData.noteHashes.filter(
1039
- s => !s.isEmpty(),
1040
- );
1041
-
1042
- const publicDataWrites = result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicDataWrites.filter(
1043
- s => !s.isEmpty(),
1044
- );
1045
- // For now, public data writes are the only merkle operations that are readable by later enqueued calls in the TXE.
1046
- await this.addPublicDataWrites(publicDataWrites);
1047
-
1048
- this.addUniqueNoteHashesFromPublic(noteHashes);
1049
-
1050
- this.addPublicLogs(
1051
- result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicLogs.filter(
1052
- log => !log.contractAddress.equals(AztecAddress.ZERO),
1053
- ),
1054
- );
1055
-
1056
- return Promise.resolve(result);
1057
- }
1058
-
1059
- async notifyEnqueuedPublicFunctionCall(
1060
- targetContractAddress: AztecAddress,
1061
- calldataHash: Fr,
1062
- _sideEffectCounter: number,
1063
- isStaticCall: boolean,
1064
- isTeardown = false,
1065
- ): Promise<void> {
1066
- // Store and modify env
1067
- const currentContractAddress = this.contractAddress;
1068
- const currentMessageSender = this.msgSender;
1069
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
1070
- const calldata = this.executionCache.getPreimage(calldataHash);
1071
- if (!calldata) {
1072
- throw new Error('Calldata for enqueued call not found in cache');
1073
- }
1074
- const functionSelector = FunctionSelector.fromField(calldata[0]);
1075
- this.setMsgSender(this.contractAddress);
1076
- this.setContractAddress(targetContractAddress);
1077
- this.setFunctionSelector(functionSelector);
1078
-
1079
- const executionResult = await this.executePublicFunction(
1080
- calldata,
1081
- /* msgSender */ currentContractAddress,
1082
- targetContractAddress,
1083
- isStaticCall,
1084
- isTeardown,
1085
- );
1086
-
1087
- // Poor man's revert handling
1088
- if (!executionResult.revertCode.isOK()) {
1089
- if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) {
1090
- await enrichPublicSimulationError(executionResult.revertReason, this.contractDataProvider, this.logger);
1091
- throw new Error(executionResult.revertReason.message);
1092
- } else {
1093
- throw new Error(`Enqueued public function call reverted: ${executionResult.revertReason}`);
1094
- }
1095
- }
1096
-
1097
- // Apply side effects
1098
- const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
1099
-
1100
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
1101
- const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
1102
- const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty()).filter(s => !s.equals(firstNullifier));
1103
-
1104
- // For some reason we cannot move this up to 'executePublicFunction'. It gives us an error of trying to modify the same nullifier twice.
1105
- this.addSiloedNullifiersFromPublic(nullifiers);
1106
-
1107
- this.setContractAddress(currentContractAddress);
1108
- this.setMsgSender(currentMessageSender);
1109
- this.setFunctionSelector(currentFunctionSelector);
1110
- }
1111
-
1112
- async notifySetPublicTeardownFunctionCall(
1113
- targetContractAddress: AztecAddress,
1114
- calldataHash: Fr,
1115
- sideEffectCounter: number,
1116
- isStaticCall: boolean,
1117
- ): Promise<void> {
1118
- // Definitely not right, in that the teardown should always be last.
1119
- // But useful for executing flows.
1120
- await this.notifyEnqueuedPublicFunctionCall(
1121
- targetContractAddress,
1122
- calldataHash,
1123
- sideEffectCounter,
1124
- isStaticCall,
1125
- /*isTeardown=*/ true,
1126
- );
1127
- }
1128
-
1129
- async notifySetMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter: number) {
1130
- await this.noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
1131
- }
1132
-
1133
- debugLog(message: string, fields: Fr[]): void {
778
+ utilityDebugLog(message: string, fields: Fr[]): void {
1134
779
  this.logger.verbose(`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
1135
780
  }
1136
781
 
1137
- async incrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<void> {
782
+ async privateIncrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<void> {
1138
783
  await this.pxeOracleInterface.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient);
1139
784
  }
1140
785
 
1141
- async getIndexedTaggingSecretAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<IndexedTaggingSecret> {
786
+ async utilityGetIndexedTaggingSecretAsSender(
787
+ sender: AztecAddress,
788
+ recipient: AztecAddress,
789
+ ): Promise<IndexedTaggingSecret> {
1142
790
  return await this.pxeOracleInterface.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient);
1143
791
  }
1144
792
 
1145
- async fetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
793
+ async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
1146
794
  await this.pxeOracleInterface.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot);
1147
795
 
1148
796
  await this.pxeOracleInterface.removeNullifiedNotes(this.contractAddress);
@@ -1150,7 +798,7 @@ export class TXE implements TypedOracle {
1150
798
  return Promise.resolve();
1151
799
  }
1152
800
 
1153
- public async validateEnqueuedNotesAndEvents(
801
+ public async utilityValidateEnqueuedNotesAndEvents(
1154
802
  contractAddress: AztecAddress,
1155
803
  noteValidationRequestsArrayBaseSlot: Fr,
1156
804
  eventValidationRequestsArrayBaseSlot: Fr,
@@ -1162,7 +810,7 @@ export class TXE implements TypedOracle {
1162
810
  );
1163
811
  }
1164
812
 
1165
- async bulkRetrieveLogs(
813
+ async utilityBulkRetrieveLogs(
1166
814
  contractAddress: AztecAddress,
1167
815
  logRetrievalRequestsArrayBaseSlot: Fr,
1168
816
  logRetrievalResponsesArrayBaseSlot: Fr,
@@ -1174,67 +822,14 @@ export class TXE implements TypedOracle {
1174
822
  );
1175
823
  }
1176
824
 
1177
- // AVM oracles
1178
-
1179
- async avmOpcodeCall(
1180
- targetContractAddress: AztecAddress,
1181
- calldata: Fr[],
1182
- isStaticCall: boolean,
1183
- ): Promise<PublicTxResult> {
1184
- // Store and modify env
1185
- const currentContractAddress = this.contractAddress;
1186
- const currentMessageSender = this.msgSender;
1187
- this.setMsgSender(this.contractAddress);
1188
- this.setContractAddress(targetContractAddress);
1189
-
1190
- const executionResult = await this.executePublicFunction(
1191
- calldata,
1192
- /* msgSender */ currentContractAddress,
1193
- targetContractAddress,
1194
- isStaticCall,
1195
- );
1196
- // Save return/revert data for later.
1197
- this.nestedCallReturndata = executionResult.processedPhases[0]!.returnValues[0].values!;
1198
- this.nestedCallSuccess = executionResult.revertCode.isOK();
1199
-
1200
- // Apply side effects
1201
- if (executionResult.revertCode.isOK()) {
1202
- const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
1203
- const publicDataWrites = sideEffects.publicDataWrites.filter(s => !s.isEmpty());
1204
- const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
1205
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
1206
- const firstNullifier = usedTxRequestHashForNonces
1207
- ? this.getTxRequestHash()
1208
- : this.noteCache.getAllNullifiers()[0];
1209
- const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty()).filter(s => !s.equals(firstNullifier));
1210
- await this.addPublicDataWrites(publicDataWrites);
1211
- this.addUniqueNoteHashesFromPublic(noteHashes);
1212
- this.addSiloedNullifiersFromPublic(nullifiers);
1213
- }
1214
-
1215
- this.setContractAddress(currentContractAddress);
1216
- this.setMsgSender(currentMessageSender);
1217
-
1218
- return executionResult;
1219
- }
1220
-
1221
- avmOpcodeSuccessCopy(): boolean {
1222
- return this.nestedCallSuccess;
1223
- }
1224
-
1225
- avmOpcodeReturndataSize(): number {
1226
- return this.nestedCallReturndata.length;
1227
- }
1228
-
1229
- avmOpcodeReturndataCopy(rdOffset: number, copySize: number): Fr[] {
1230
- return this.nestedCallReturndata.slice(rdOffset, rdOffset + copySize);
1231
- }
1232
-
1233
825
  async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
1234
826
  const nullifier = await siloNullifier(targetAddress, innerNullifier!);
1235
827
  const db = this.baseFork;
1236
- const index = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0];
1237
- return index !== undefined;
828
+
829
+ const treeIndex = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]))[0];
830
+ const transientIndex = this.siloedNullifiersFromPublic.find(n => n.equals(nullifier));
831
+
832
+ return treeIndex !== undefined || transientIndex !== undefined;
1238
833
  }
1239
834
 
1240
835
  async avmOpcodeEmitNullifier(nullifier: Fr) {
@@ -1267,7 +862,7 @@ export class TXE implements TypedOracle {
1267
862
  return preimage.leaf.value;
1268
863
  }
1269
864
 
1270
- storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
865
+ utilityStoreCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
1271
866
  if (!contractAddress.equals(this.contractAddress)) {
1272
867
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
1273
868
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
@@ -1275,7 +870,7 @@ export class TXE implements TypedOracle {
1275
870
  return this.pxeOracleInterface.storeCapsule(this.contractAddress, slot, capsule);
1276
871
  }
1277
872
 
1278
- loadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
873
+ utilityLoadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
1279
874
  if (!contractAddress.equals(this.contractAddress)) {
1280
875
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
1281
876
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
@@ -1283,7 +878,7 @@ export class TXE implements TypedOracle {
1283
878
  return this.pxeOracleInterface.loadCapsule(this.contractAddress, slot);
1284
879
  }
1285
880
 
1286
- deleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
881
+ utilityDeleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
1287
882
  if (!contractAddress.equals(this.contractAddress)) {
1288
883
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
1289
884
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
@@ -1291,7 +886,7 @@ export class TXE implements TypedOracle {
1291
886
  return this.pxeOracleInterface.deleteCapsule(this.contractAddress, slot);
1292
887
  }
1293
888
 
1294
- copyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
889
+ utilityCopyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
1295
890
  if (!contractAddress.equals(this.contractAddress)) {
1296
891
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
1297
892
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
@@ -1299,21 +894,25 @@ export class TXE implements TypedOracle {
1299
894
  return this.pxeOracleInterface.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries);
1300
895
  }
1301
896
 
1302
- aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
897
+ utilityAes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
1303
898
  const aes128 = new Aes128();
1304
899
  return aes128.decryptBufferCBC(ciphertext, iv, symKey);
1305
900
  }
1306
901
 
1307
- getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
902
+ utilityGetSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
1308
903
  return this.pxeOracleInterface.getSharedSecret(address, ephPk);
1309
904
  }
1310
905
 
1311
- emitOffchainEffect(_data: Fr[]) {
1312
- // Offchain effects are discarded in TXE tests.
906
+ privateGetSenderForTags(): Promise<AztecAddress | undefined> {
907
+ return Promise.resolve(this.senderForTags);
908
+ }
909
+
910
+ privateSetSenderForTags(senderForTags: AztecAddress): Promise<void> {
911
+ this.senderForTags = senderForTags;
1313
912
  return Promise.resolve();
1314
913
  }
1315
914
 
1316
- async privateCallNewFlow(
915
+ async txePrivateCallNewFlow(
1317
916
  from: AztecAddress,
1318
917
  targetContractAddress: AztecAddress = AztecAddress.zero(),
1319
918
  functionSelector: FunctionSelector = FunctionSelector.empty(),
@@ -1331,7 +930,13 @@ export class TXE implements TypedOracle {
1331
930
  const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
1332
931
 
1333
932
  if (artifact === undefined) {
1334
- throw new Error('Function Artifact does not exist');
933
+ if (functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))) {
934
+ throw new Error(
935
+ 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.',
936
+ );
937
+ } else {
938
+ throw new Error('Function Artifact does not exist');
939
+ }
1335
940
  }
1336
941
 
1337
942
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
@@ -1348,6 +953,7 @@ export class TXE implements TypedOracle {
1348
953
 
1349
954
  const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
1350
955
 
956
+ // TODO(benesjan): Fix stale 'context' name.
1351
957
  const context = new PrivateExecutionOracle(
1352
958
  argsHash,
1353
959
  txContext,
@@ -1355,7 +961,7 @@ export class TXE implements TypedOracle {
1355
961
  /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
1356
962
  blockHeader,
1357
963
  /** List of transient auth witnesses to be used during this simulation */
1358
- [],
964
+ Array.from(this.authwits.values()),
1359
965
  /** List of transient auth witnesses to be used during this simulation */
1360
966
  [],
1361
967
  HashedValuesCache.create(),
@@ -1364,9 +970,16 @@ export class TXE implements TypedOracle {
1364
970
  this.simulator,
1365
971
  0,
1366
972
  1,
973
+ undefined, // log
974
+ undefined, // scopes
975
+ /**
976
+ * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
977
+ * contract would perform, including setting senderForTags.
978
+ */
979
+ from,
1367
980
  );
1368
981
 
1369
- context.storeInExecutionCache(args, argsHash);
982
+ context.privateStoreInExecutionCache(args, argsHash);
1370
983
 
1371
984
  // Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
1372
985
  let result: PrivateExecutionResult;
@@ -1382,13 +995,15 @@ export class TXE implements TypedOracle {
1382
995
  const { usedTxRequestHashForNonces } = noteCache.finish();
1383
996
  const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
1384
997
 
1385
- const publicCallRequests = collectNested([executionResult], r => [
1386
- ...r.publicInputs.publicCallRequests.map(r => r.inner),
1387
- r.publicInputs.publicTeardownCallRequest,
1388
- ]).filter(r => !r.isEmpty());
998
+ const publicCallRequests = collectNested([executionResult], r =>
999
+ r.publicInputs.publicCallRequests
1000
+ .getActiveItems()
1001
+ .map(r => r.inner)
1002
+ .concat(r.publicInputs.publicTeardownCallRequest.isEmpty() ? [] : [r.publicInputs.publicTeardownCallRequest]),
1003
+ );
1389
1004
  const publicFunctionsCalldata = await Promise.all(
1390
1005
  publicCallRequests.map(async r => {
1391
- const calldata = await context.loadFromExecutionCache(r.calldataHash);
1006
+ const calldata = await context.privateLoadFromExecutionCache(r.calldataHash);
1392
1007
  return new HashedValues(calldata, r.calldataHash);
1393
1008
  }),
1394
1009
  );
@@ -1403,7 +1018,7 @@ export class TXE implements TypedOracle {
1403
1018
  // This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
1404
1019
  // Investigate whether it is faster to do this or return from the oracle directly.
1405
1020
  const returnValuesHash = await computeVarArgsHash(returnValues);
1406
- this.storeInExecutionCache(returnValues, returnValuesHash);
1021
+ this.privateStoreInExecutionCache(returnValues, returnValuesHash);
1407
1022
  }
1408
1023
 
1409
1024
  // According to the protocol rules, the nonce generator for the note hashes
@@ -1415,6 +1030,8 @@ export class TXE implements TypedOracle {
1415
1030
  const globals = makeGlobalVariables();
1416
1031
  globals.blockNumber = this.blockNumber;
1417
1032
  globals.timestamp = this.timestamp;
1033
+ globals.chainId = new Fr(this.CHAIN_ID);
1034
+ globals.version = new Fr(this.ROLLUP_VERSION);
1418
1035
  globals.gasFees = GasFees.empty();
1419
1036
 
1420
1037
  const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
@@ -1422,7 +1039,12 @@ export class TXE implements TypedOracle {
1422
1039
  const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
1423
1040
  const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
1424
1041
 
1425
- const tx = new Tx(publicInputs, ClientIvcProof.empty(), [], result.publicFunctionCalldata);
1042
+ const tx = await Tx.create({
1043
+ data: publicInputs,
1044
+ clientIvcProof: ClientIvcProof.empty(),
1045
+ contractClassLogFields: [],
1046
+ publicFunctionCalldata: result.publicFunctionCalldata,
1047
+ });
1426
1048
 
1427
1049
  let checkpoint;
1428
1050
  if (isStaticCall) {
@@ -1431,21 +1053,27 @@ export class TXE implements TypedOracle {
1431
1053
 
1432
1054
  const results = await processor.process([tx]);
1433
1055
 
1434
- const processedTxs = results[0];
1056
+ const [processedTx] = results[0];
1435
1057
  const failedTxs = results[1];
1436
1058
 
1437
1059
  if (failedTxs.length !== 0) {
1438
- throw new Error('Public execution has failed');
1060
+ throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
1061
+ } else if (!processedTx.revertCode.isOK()) {
1062
+ if (processedTx.revertReason) {
1063
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
1064
+ throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
1065
+ } else {
1066
+ throw new Error('Contract execution has reverted');
1067
+ }
1439
1068
  }
1440
1069
 
1441
1070
  if (isStaticCall) {
1442
1071
  await checkpoint!.revert();
1443
- const txRequestHash = this.getTxRequestHash();
1444
1072
 
1445
1073
  return {
1446
1074
  endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
1447
1075
  returnsHash: result.entrypoint.publicInputs.returnsHash,
1448
- txHash: txRequestHash,
1076
+ txHash: tx.getTxHash(),
1449
1077
  };
1450
1078
  }
1451
1079
 
@@ -1453,11 +1081,11 @@ export class TXE implements TypedOracle {
1453
1081
 
1454
1082
  const txEffect = TxEffect.empty();
1455
1083
 
1456
- txEffect.noteHashes = processedTxs[0]!.txEffect.noteHashes;
1457
- txEffect.nullifiers = processedTxs[0]!.txEffect.nullifiers;
1458
- txEffect.privateLogs = processedTxs[0]!.txEffect.privateLogs;
1459
- txEffect.publicLogs = processedTxs[0]!.txEffect.publicLogs;
1460
- txEffect.publicDataWrites = processedTxs[0]!.txEffect.publicDataWrites;
1084
+ txEffect.noteHashes = processedTx!.txEffect.noteHashes;
1085
+ txEffect.nullifiers = processedTx!.txEffect.nullifiers;
1086
+ txEffect.privateLogs = processedTx!.txEffect.privateLogs;
1087
+ txEffect.publicLogs = processedTx!.txEffect.publicLogs;
1088
+ txEffect.publicDataWrites = processedTx!.txEffect.publicDataWrites;
1461
1089
 
1462
1090
  txEffect.txHash = new TxHash(new Fr(this.blockNumber));
1463
1091
 
@@ -1492,18 +1120,15 @@ export class TXE implements TypedOracle {
1492
1120
 
1493
1121
  await this.stateMachine.handleL2Block(l2Block);
1494
1122
 
1495
- const txRequestHash = this.getTxRequestHash();
1496
-
1497
1123
  this.setBlockNumber(this.blockNumber + 1);
1498
- this.advanceTimestampBy(AZTEC_SLOT_DURATION);
1499
1124
  return {
1500
1125
  endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
1501
1126
  returnsHash: result.entrypoint.publicInputs.returnsHash,
1502
- txHash: txRequestHash,
1127
+ txHash: tx.getTxHash(),
1503
1128
  };
1504
1129
  }
1505
1130
 
1506
- async publicCallNewFlow(
1131
+ async txePublicCallNewFlow(
1507
1132
  from: AztecAddress,
1508
1133
  targetContractAddress: AztecAddress,
1509
1134
  calldata: Fr[],
@@ -1526,22 +1151,14 @@ export class TXE implements TypedOracle {
1526
1151
 
1527
1152
  const blockHeader = await this.pxeOracleInterface.getBlockHeader();
1528
1153
 
1529
- const uniqueNoteHashes: Fr[] = [];
1530
- const taggedPrivateLogs: PrivateLog[] = [];
1531
- const nullifiers: Fr[] = !isStaticCall ? [this.getTxRequestHash()] : [];
1532
- const l2ToL1Messages: ScopedL2ToL1Message[] = [];
1533
- const contractClassLogsHashes: ScopedLogHash[] = [];
1534
-
1535
1154
  const calldataHash = await computeCalldataHash(calldata);
1536
-
1537
1155
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
1538
1156
 
1539
- const publicCallRequest = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
1540
- const publicCallRequests: PublicCallRequest[] = [publicCallRequest];
1541
-
1542
1157
  const globals = makeGlobalVariables();
1543
1158
  globals.blockNumber = this.blockNumber;
1544
1159
  globals.timestamp = this.timestamp;
1160
+ globals.chainId = new Fr(this.CHAIN_ID);
1161
+ globals.version = new Fr(this.ROLLUP_VERSION);
1545
1162
  globals.gasFees = GasFees.empty();
1546
1163
 
1547
1164
  const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
@@ -1549,36 +1166,48 @@ export class TXE implements TypedOracle {
1549
1166
  const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
1550
1167
  const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
1551
1168
 
1552
- const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
1169
+ // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
1170
+ // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
1171
+ // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
1172
+ // unique.
1173
+ const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
1174
+ if (!isStaticCall) {
1175
+ nonRevertibleAccumulatedData.nullifiers[0] = this.getTxRequestHash();
1176
+ }
1553
1177
 
1554
- const accumulatedDataForPublic = new PrivateToPublicAccumulatedData(
1555
- padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
1556
- padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
1557
- padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
1558
- padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
1559
- padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
1560
- padArrayEnd(publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
1178
+ // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
1179
+ // may require producing reverts.
1180
+ const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
1181
+ revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
1182
+ from,
1183
+ targetContractAddress,
1184
+ isStaticCall,
1185
+ calldataHash,
1561
1186
  );
1562
1187
 
1563
1188
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
1564
- // nonrevertible
1565
- PrivateToPublicAccumulatedData.empty(),
1566
- // revertible
1567
- // We are using revertible (app phase) because only the app-phase returns are exposed.
1568
- accumulatedDataForPublic,
1189
+ nonRevertibleAccumulatedData,
1190
+ revertibleAccumulatedData,
1569
1191
  PublicCallRequest.empty(),
1570
1192
  );
1571
1193
 
1194
+ const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
1195
+
1572
1196
  const txData = new PrivateKernelTailCircuitPublicInputs(
1573
1197
  constantData,
1574
- RollupValidationRequests.empty(),
1575
1198
  /*gasUsed=*/ new Gas(0, 0),
1576
1199
  /*feePayer=*/ AztecAddress.zero(),
1200
+ /*includeByTimestamp=*/ 0n,
1577
1201
  inputsForPublic,
1578
1202
  undefined,
1579
1203
  );
1580
1204
 
1581
- const tx = new Tx(txData, ClientIvcProof.empty(), [], [calldataHashedValues]);
1205
+ const tx = await Tx.create({
1206
+ data: txData,
1207
+ clientIvcProof: ClientIvcProof.empty(),
1208
+ contractClassLogFields: [],
1209
+ publicFunctionCalldata: [calldataHashedValues],
1210
+ });
1582
1211
 
1583
1212
  let checkpoint;
1584
1213
  if (isStaticCall) {
@@ -1587,11 +1216,18 @@ export class TXE implements TypedOracle {
1587
1216
 
1588
1217
  const results = await processor.process([tx]);
1589
1218
 
1590
- const processedTxs = results[0];
1219
+ const [processedTx] = results[0];
1591
1220
  const failedTxs = results[1];
1592
1221
 
1593
- if (failedTxs.length !== 0 || !processedTxs[0].revertCode.isOK()) {
1594
- throw new Error('Public execution has failed');
1222
+ if (failedTxs.length !== 0) {
1223
+ throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
1224
+ } else if (!processedTx.revertCode.isOK()) {
1225
+ if (processedTx.revertReason) {
1226
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
1227
+ throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
1228
+ } else {
1229
+ throw new Error('Contract execution has reverted');
1230
+ }
1595
1231
  }
1596
1232
 
1597
1233
  const returnValues = results[3][0].values;
@@ -1601,16 +1237,15 @@ export class TXE implements TypedOracle {
1601
1237
  // This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
1602
1238
  // Investigate whether it is faster to do this or return from the oracle directly.
1603
1239
  returnValuesHash = await computeVarArgsHash(returnValues);
1604
- this.storeInExecutionCache(returnValues, returnValuesHash);
1240
+ this.privateStoreInExecutionCache(returnValues, returnValuesHash);
1605
1241
  }
1606
1242
 
1607
1243
  if (isStaticCall) {
1608
1244
  await checkpoint!.revert();
1609
- const txRequestHash = this.getTxRequestHash();
1610
1245
 
1611
1246
  return {
1612
1247
  returnsHash: returnValuesHash ?? Fr.ZERO,
1613
- txHash: txRequestHash,
1248
+ txHash: tx.getTxHash(),
1614
1249
  };
1615
1250
  }
1616
1251
 
@@ -1618,11 +1253,11 @@ export class TXE implements TypedOracle {
1618
1253
 
1619
1254
  const txEffect = TxEffect.empty();
1620
1255
 
1621
- txEffect.noteHashes = processedTxs[0]!.txEffect.noteHashes;
1622
- txEffect.nullifiers = processedTxs[0]!.txEffect.nullifiers;
1623
- txEffect.privateLogs = taggedPrivateLogs;
1624
- txEffect.publicLogs = processedTxs[0]!.txEffect.publicLogs;
1625
- txEffect.publicDataWrites = processedTxs[0]!.txEffect.publicDataWrites;
1256
+ txEffect.noteHashes = processedTx!.txEffect.noteHashes;
1257
+ txEffect.nullifiers = processedTx!.txEffect.nullifiers;
1258
+ txEffect.privateLogs = processedTx!.txEffect.privateLogs;
1259
+ txEffect.publicLogs = processedTx!.txEffect.publicLogs;
1260
+ txEffect.publicDataWrites = processedTx!.txEffect.publicDataWrites;
1626
1261
 
1627
1262
  txEffect.txHash = new TxHash(new Fr(this.blockNumber));
1628
1263
 
@@ -1657,14 +1292,20 @@ export class TXE implements TypedOracle {
1657
1292
 
1658
1293
  await this.stateMachine.handleL2Block(l2Block);
1659
1294
 
1660
- const txRequestHash = this.getTxRequestHash();
1661
-
1662
1295
  this.setBlockNumber(this.blockNumber + 1);
1663
- this.advanceTimestampBy(AZTEC_SLOT_DURATION);
1664
1296
 
1665
1297
  return {
1666
1298
  returnsHash: returnValuesHash ?? Fr.ZERO,
1667
- txHash: txRequestHash,
1299
+ txHash: tx.getTxHash(),
1668
1300
  };
1669
1301
  }
1302
+
1303
+ private async getBlockTimestamp(blockNumber: number) {
1304
+ const blockHeader = await this.stateMachine.archiver.getBlockHeader(blockNumber);
1305
+ if (!blockHeader) {
1306
+ throw new Error(`Requested timestamp for block ${blockNumber}, which does not exist`);
1307
+ }
1308
+
1309
+ return blockHeader.globalVariables.timestamp;
1310
+ }
1670
1311
  }