@aztec/txe 1.2.0 → 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.
@@ -1,34 +1,29 @@
1
1
  import { Body, L2Block, Note } from '@aztec/aztec.js';
2
- import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT, MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_GAS_PER_TX_PUBLIC_PORTION, MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_CONTEXT_INPUTS_LENGTH } from '@aztec/constants';
2
+ import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_CONTEXT_INPUTS_LENGTH } from '@aztec/constants';
3
3
  import { padArrayEnd } from '@aztec/foundation/collection';
4
- import { Aes128, Schnorr, poseidon2Hash } from '@aztec/foundation/crypto';
4
+ import { Aes128, Schnorr } from '@aztec/foundation/crypto';
5
5
  import { Fr } from '@aztec/foundation/fields';
6
6
  import { applyStringFormatting } from '@aztec/foundation/log';
7
- import { TestDateProvider, Timer } from '@aztec/foundation/timer';
7
+ import { TestDateProvider } from '@aztec/foundation/timer';
8
8
  import { KeyStore } from '@aztec/key-store';
9
9
  import { AddressDataProvider, CapsuleDataProvider, NoteDataProvider, PXEOracleInterface, PrivateEventDataProvider, TaggingDataProvider, enrichPublicSimulationError } from '@aztec/pxe/server';
10
- import { ExecutionNoteCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, extractPrivateCircuitPublicInputs, generateSimulatedProvingResult, pickNotes } from '@aztec/pxe/simulator';
10
+ import { ExecutionNoteCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult, pickNotes } from '@aztec/pxe/simulator';
11
11
  import { WASMSimulator, extractCallStack, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
12
- import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
13
12
  import { ExecutionError, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, PublicTxSimulator, createSimulationError, resolveAssertionMessageFromError } from '@aztec/simulator/server';
14
13
  import { FunctionSelector, FunctionType, countArgumentsSize } from '@aztec/stdlib/abi';
15
14
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
16
15
  import { PublicDataWrite } from '@aztec/stdlib/avm';
17
16
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
18
- import { SimulationError } from '@aztec/stdlib/errors';
19
17
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
20
18
  import { computeCalldataHash, computeNoteHashNonce, computePublicDataTreeLeafSlot, computeUniqueNoteHash, computeVarArgsHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
21
- import { PartialPrivateTailPublicInputsForPublic, PrivateContextInputs, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest, RollupValidationRequests, ScopedLogHash } from '@aztec/stdlib/kernel';
22
- import { deriveKeys } from '@aztec/stdlib/keys';
23
- import { PrivateLog } from '@aztec/stdlib/logs';
24
- import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
19
+ import { PartialPrivateTailPublicInputsForPublic, PrivateContextInputs, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
25
20
  import { ClientIvcProof } from '@aztec/stdlib/proofs';
26
21
  import { makeAppendOnlyTreeSnapshot, makeContentCommitment, makeGlobalVariables, makeHeader } from '@aztec/stdlib/testing';
27
- import { AppendOnlyTreeSnapshot, MerkleTreeId, NullifierMembershipWitness, PublicDataTreeLeaf, PublicDataWitness } from '@aztec/stdlib/trees';
28
- import { BlockHeader, CallContext, GlobalVariables, HashedValues, PrivateExecutionResult, PublicCallRequestWithCalldata, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
22
+ import { AppendOnlyTreeSnapshot, MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
23
+ import { BlockHeader, CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
29
24
  import { ForkCheckpoint } from '@aztec/world-state/native';
30
25
  import { TXEStateMachine } from '../state_machine/index.js';
31
- import { AZTEC_SLOT_DURATION, GENESIS_TIMESTAMP } from '../txe_constants.js';
26
+ import { GENESIS_TIMESTAMP } from '../txe_constants.js';
32
27
  import { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
33
28
  import { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
34
29
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
@@ -53,10 +48,6 @@ export class TXE {
53
48
  sideEffectCounter;
54
49
  msgSender;
55
50
  functionSelector;
56
- isStaticCall;
57
- // Return/revert data of the latest nested call.
58
- nestedCallReturndata;
59
- nestedCallSuccess;
60
51
  pxeOracleInterface;
61
52
  publicDataWrites;
62
53
  uniqueNoteHashesFromPublic;
@@ -70,6 +61,8 @@ export class TXE {
70
61
  simulator;
71
62
  noteCache;
72
63
  authwits;
64
+ // Used by privateSetSenderForTags and privateGetSenderForTags oracles.
65
+ senderForTags;
73
66
  constructor(logger, keyStore, contractDataProvider, noteDataProvider, capsuleDataProvider, syncDataProvider, taggingDataProvider, addressDataProvider, privateEventDataProvider, accountDataProvider, executionCache, contractAddress, nativeWorldStateService, baseFork, stateMachine){
74
67
  this.logger = logger;
75
68
  this.keyStore = keyStore;
@@ -90,9 +83,6 @@ export class TXE {
90
83
  this.timestamp = GENESIS_TIMESTAMP;
91
84
  this.sideEffectCounter = 0;
92
85
  this.functionSelector = FunctionSelector.fromField(new Fr(0));
93
- this.isStaticCall = false;
94
- this.nestedCallReturndata = [];
95
- this.nestedCallSuccess = false;
96
86
  this.publicDataWrites = [];
97
87
  this.uniqueNoteHashesFromPublic = [];
98
88
  this.siloedNullifiersFromPublic = [];
@@ -137,38 +127,23 @@ export class TXE {
137
127
  getBaseFork() {
138
128
  return this.baseFork;
139
129
  }
140
- getChainId() {
130
+ utilityGetChainId() {
141
131
  return Promise.resolve(new Fr(this.CHAIN_ID));
142
132
  }
143
- getVersion() {
133
+ utilityGetVersion() {
144
134
  return Promise.resolve(new Fr(this.ROLLUP_VERSION));
145
135
  }
146
136
  getMsgSender() {
147
137
  return this.msgSender;
148
138
  }
149
- getFunctionSelector() {
150
- return this.functionSelector;
151
- }
152
- setMsgSender(msgSender) {
153
- this.msgSender = msgSender;
154
- }
155
- setFunctionSelector(functionSelector) {
156
- this.functionSelector = functionSelector;
157
- }
158
- getSideEffectsCounter() {
159
- return this.sideEffectCounter;
160
- }
161
- setSideEffectsCounter(sideEffectsCounter) {
162
- this.sideEffectCounter = sideEffectsCounter;
163
- }
164
- setContractAddress(contractAddress) {
139
+ txeSetContractAddress(contractAddress) {
165
140
  this.contractAddress = contractAddress;
166
141
  }
167
142
  // TODO: Currently this is only ever used to increment this.blockNumber by 1. Refactor this as `advanceBlock()`.
168
143
  setBlockNumber(blockNumber) {
169
144
  this.blockNumber = blockNumber;
170
145
  }
171
- advanceTimestampBy(duration) {
146
+ txeAdvanceTimestampBy(duration) {
172
147
  this.timestamp = this.timestamp + duration;
173
148
  }
174
149
  getContractDataProvider() {
@@ -189,11 +164,10 @@ export class TXE {
189
164
  async addContractArtifact(contractClassId, artifact) {
190
165
  await this.contractDataProvider.addContractArtifact(contractClassId, artifact);
191
166
  }
192
- async getPrivateContextInputs(blockNumber, timestamp, sideEffectsCounter = this.sideEffectCounter, isStaticCall = false) {
167
+ async txeGetPrivateContextInputs(blockNumber, sideEffectsCounter = this.sideEffectCounter, isStaticCall = false) {
193
168
  // If blockNumber or timestamp is null, use the values corresponding to the latest historical block (number of
194
169
  // the block being built - 1)
195
170
  blockNumber = blockNumber ?? this.blockNumber - 1;
196
- timestamp = timestamp ?? this.timestamp - AZTEC_SLOT_DURATION;
197
171
  const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
198
172
  const previousBlockState = this.nativeWorldStateService.getSnapshot(blockNumber - 1);
199
173
  const stateReference = await snap.getStateReference();
@@ -201,17 +175,14 @@ export class TXE {
201
175
  inputs.txContext.chainId = new Fr(this.CHAIN_ID);
202
176
  inputs.txContext.version = new Fr(this.ROLLUP_VERSION);
203
177
  inputs.historicalHeader.globalVariables.blockNumber = blockNumber;
204
- inputs.historicalHeader.globalVariables.timestamp = timestamp;
178
+ inputs.historicalHeader.globalVariables.timestamp = await this.getBlockTimestamp(blockNumber);
205
179
  inputs.historicalHeader.state = stateReference;
206
180
  inputs.historicalHeader.lastArchive.root = Fr.fromBuffer((await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root);
207
181
  inputs.callContext = new CallContext(this.msgSender, this.contractAddress, this.functionSelector, isStaticCall);
208
182
  inputs.startSideEffectCounter = sideEffectsCounter;
209
183
  return inputs;
210
184
  }
211
- deriveKeys(secret) {
212
- return deriveKeys(secret);
213
- }
214
- async addAuthWitness(address, messageHash) {
185
+ async txeAddAuthWitness(address, messageHash) {
215
186
  const account = await this.accountDataProvider.getAccount(address);
216
187
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
217
188
  const schnorr = new Schnorr();
@@ -239,139 +210,61 @@ export class TXE {
239
210
  addUniqueNoteHashesFromPublic(siloedNoteHashes) {
240
211
  this.uniqueNoteHashesFromPublic.push(...siloedNoteHashes);
241
212
  }
242
- async addPrivateLogs(contractAddress, privateLogs) {
243
- for (const privateLog of privateLogs){
244
- privateLog.fields[0] = await poseidon2Hash([
245
- contractAddress,
246
- privateLog.fields[0]
247
- ]);
248
- }
249
- this.privateLogs.push(...privateLogs);
250
- }
251
- addPublicLogs(logs) {
252
- logs.forEach((log)=>{
253
- try {
254
- const tag = log.fields[0];
255
- this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
256
- this.publicLogs.push(log);
257
- } catch (err) {
258
- this.logger.warn(`Failed to add tagged log to store: ${err}`);
259
- }
260
- });
261
- }
262
213
  // TypedOracle
263
- getBlockNumber() {
214
+ utilityGetBlockNumber() {
264
215
  return Promise.resolve(this.blockNumber);
265
216
  }
266
- getTimestamp() {
217
+ utilityGetTimestamp() {
267
218
  return Promise.resolve(this.timestamp);
268
219
  }
269
- getContractAddress() {
270
- return Promise.resolve(this.contractAddress);
271
- }
272
- setIsStaticCall(isStatic) {
273
- this.isStaticCall = isStatic;
220
+ txeGetLastBlockTimestamp() {
221
+ return this.getBlockTimestamp(this.blockNumber - 1);
274
222
  }
275
- getIsStaticCall() {
276
- return this.isStaticCall;
223
+ utilityGetContractAddress() {
224
+ return Promise.resolve(this.contractAddress);
277
225
  }
278
- getRandomField() {
226
+ utilityGetRandomField() {
279
227
  return Fr.random();
280
228
  }
281
- storeInExecutionCache(values, hash) {
229
+ privateStoreInExecutionCache(values, hash) {
282
230
  return this.executionCache.store(values, hash);
283
231
  }
284
- loadFromExecutionCache(hash) {
232
+ privateLoadFromExecutionCache(hash) {
285
233
  const preimage = this.executionCache.getPreimage(hash);
286
234
  if (!preimage) {
287
235
  throw new Error(`Preimage for hash ${hash.toString()} not found in cache`);
288
236
  }
289
237
  return Promise.resolve(preimage);
290
238
  }
291
- getKeyValidationRequest(pkMHash) {
239
+ utilityGetKeyValidationRequest(pkMHash) {
292
240
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
293
241
  }
294
- async getContractInstance(address) {
295
- const contractInstance = await this.contractDataProvider.getContractInstance(address);
296
- if (!contractInstance) {
297
- throw new Error(`Contract instance not found for address ${address}`);
298
- }
299
- return contractInstance;
242
+ utilityGetContractInstance(address) {
243
+ return this.pxeOracleInterface.getContractInstance(address);
300
244
  }
301
- async getMembershipWitness(blockNumber, treeId, leafValue) {
302
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
303
- const index = (await snap.findLeafIndices(treeId, [
304
- leafValue.toBuffer()
305
- ]))[0];
306
- if (index === undefined) {
307
- throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
308
- }
309
- const siblingPath = await snap.getSiblingPath(treeId, index);
310
- return [
311
- new Fr(index),
312
- ...siblingPath.toFields()
313
- ];
245
+ utilityGetMembershipWitness(blockNumber, treeId, leafValue) {
246
+ return this.pxeOracleInterface.getMembershipWitness(blockNumber, treeId, leafValue);
314
247
  }
315
- async getSiblingPath(blockNumber, treeId, leafIndex) {
316
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
317
- const result = await snap.getSiblingPath(treeId, leafIndex.toBigInt());
318
- return result.toFields();
248
+ utilityGetNullifierMembershipWitness(blockNumber, nullifier) {
249
+ return this.pxeOracleInterface.getNullifierMembershipWitness(blockNumber, nullifier);
319
250
  }
320
- async getNullifierMembershipWitness(blockNumber, nullifier) {
321
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
322
- const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
323
- nullifier.toBuffer()
324
- ]);
325
- if (!index) {
326
- return undefined;
327
- }
328
- const leafPreimagePromise = snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
329
- const siblingPathPromise = snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
330
- const [leafPreimage, siblingPath] = await Promise.all([
331
- leafPreimagePromise,
332
- siblingPathPromise
333
- ]);
334
- if (!leafPreimage) {
335
- return undefined;
336
- }
337
- return new NullifierMembershipWitness(BigInt(index), leafPreimage, siblingPath);
338
- }
339
- async getPublicDataWitness(blockNumber, leafSlot) {
340
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
341
- const lowLeafResult = await snap.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
342
- if (!lowLeafResult) {
343
- return undefined;
344
- } else {
345
- const preimage = await snap.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
346
- const path = await snap.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
347
- return new PublicDataWitness(lowLeafResult.index, preimage, path);
348
- }
251
+ utilityGetPublicDataWitness(blockNumber, leafSlot) {
252
+ return this.pxeOracleInterface.getPublicDataWitness(blockNumber, leafSlot);
349
253
  }
350
- async getLowNullifierMembershipWitness(blockNumber, nullifier) {
351
- const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
352
- const findResult = await snap.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
353
- if (!findResult) {
354
- return undefined;
355
- }
356
- const { index, alreadyPresent } = findResult;
357
- if (alreadyPresent) {
358
- this.logger.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
359
- }
360
- const preimageData = await snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
361
- const siblingPath = await snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
362
- return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
254
+ utilityGetLowNullifierMembershipWitness(blockNumber, nullifier) {
255
+ return this.pxeOracleInterface.getLowNullifierMembershipWitness(blockNumber, nullifier);
363
256
  }
364
- getBlockHeader(blockNumber) {
257
+ utilityGetBlockHeader(blockNumber) {
365
258
  return this.stateMachine.archiver.getBlockHeader(blockNumber);
366
259
  }
367
- getCompleteAddress(account) {
260
+ utilityGetCompleteAddress(account) {
368
261
  return Promise.resolve(this.accountDataProvider.getAccount(account));
369
262
  }
370
- getAuthWitness(messageHash) {
263
+ utilityGetAuthWitness(messageHash) {
371
264
  const authwit = this.authwits.get(messageHash.toString());
372
265
  return Promise.resolve(authwit?.witness);
373
266
  }
374
- async getNotes(storageSlot, numSelects, selectByIndexes, selectByOffsets, selectByLengths, selectValues, selectComparators, sortByIndexes, sortByOffsets, sortByLengths, sortOrder, limit, offset, status) {
267
+ async utilityGetNotes(storageSlot, numSelects, selectByIndexes, selectByOffsets, selectByLengths, selectValues, selectComparators, sortByIndexes, sortByOffsets, sortByLengths, sortOrder, limit, offset, status) {
375
268
  // Nullified pending notes are already removed from the list.
376
269
  const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
377
270
  const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress);
@@ -404,7 +297,7 @@ export class TXE {
404
297
  this.logger.debug(`Returning ${notes.length} notes for ${this.contractAddress} at ${storageSlot}: ${notes.map((n)=>`${n.noteNonce.toString()}:[${n.note.items.map((i)=>i.toString()).join(',')}]`).join(', ')}`);
405
298
  return notes;
406
299
  }
407
- notifyCreatedNote(storageSlot, _noteTypeId, noteItems, noteHash, counter) {
300
+ privateNotifyCreatedNote(storageSlot, _noteTypeId, noteItems, noteHash, counter) {
408
301
  const note = new Note(noteItems);
409
302
  this.noteCache.addNewNote({
410
303
  contractAddress: this.contractAddress,
@@ -416,31 +309,32 @@ export class TXE {
416
309
  }, counter);
417
310
  this.sideEffectCounter = counter + 1;
418
311
  }
419
- async notifyNullifiedNote(innerNullifier, noteHash, counter) {
312
+ async privateNotifyNullifiedNote(innerNullifier, noteHash, counter) {
420
313
  await this.checkNullifiersNotInTree(this.contractAddress, [
421
314
  innerNullifier
422
315
  ]);
423
316
  await this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
424
317
  this.sideEffectCounter = counter + 1;
425
318
  }
426
- async notifyCreatedNullifier(innerNullifier) {
319
+ async privateNotifyCreatedNullifier(innerNullifier) {
427
320
  await this.checkNullifiersNotInTree(this.contractAddress, [
428
321
  innerNullifier
429
322
  ]);
430
323
  await this.noteCache.nullifierCreated(this.contractAddress, innerNullifier);
431
324
  }
432
- async checkNullifierExists(innerNullifier) {
325
+ async utilityCheckNullifierExists(innerNullifier) {
433
326
  const snap = this.nativeWorldStateService.getSnapshot(this.blockNumber - 1);
434
327
  const nullifier = await siloNullifier(this.contractAddress, innerNullifier);
435
328
  const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
436
329
  nullifier.toBuffer()
437
330
  ]);
438
- return index !== undefined;
331
+ const inPendingCache = this.noteCache.getNullifiers(this.contractAddress).has(nullifier.toBigInt());
332
+ return index !== undefined || inPendingCache;
439
333
  }
440
334
  getL1ToL2MembershipWitness(_contractAddress, _messageHash, _secret) {
441
335
  throw new Error('Method not implemented.');
442
336
  }
443
- async storageRead(contractAddress, startStorageSlot, blockNumber, numberOfElements) {
337
+ async utilityStorageRead(contractAddress, startStorageSlot, blockNumber, numberOfElements) {
444
338
  let db;
445
339
  if (blockNumber === this.blockNumber) {
446
340
  db = this.baseFork;
@@ -472,7 +366,7 @@ export class TXE {
472
366
  return publicDataWrites.map((write)=>write.value);
473
367
  }
474
368
  async commitState() {
475
- const blockNumber = await this.getBlockNumber();
369
+ const blockNumber = await this.utilityGetBlockNumber();
476
370
  const { usedTxRequestHashForNonces } = this.noteCache.finish();
477
371
  if (this.committedBlocks.has(blockNumber)) {
478
372
  throw new Error('Already committed state');
@@ -524,7 +418,10 @@ export class TXE {
524
418
  const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
525
419
  const header = new BlockHeader(new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)), makeContentCommitment(), stateReference, makeGlobalVariables(), Fr.ZERO, Fr.ZERO);
526
420
  header.globalVariables.blockNumber = blockNumber;
527
- header.globalVariables.timestamp = await this.getTimestamp();
421
+ header.globalVariables.timestamp = await this.utilityGetTimestamp();
422
+ header.globalVariables.version = new Fr(this.ROLLUP_VERSION);
423
+ header.globalVariables.chainId = new Fr(this.CHAIN_ID);
424
+ this.logger.info(`Created block ${blockNumber} with timestamp ${header.globalVariables.timestamp}`);
528
425
  l2Block.header = header;
529
426
  await fork.updateArchive(l2Block.header);
530
427
  await this.stateMachine.handleL2Block(l2Block);
@@ -562,7 +459,7 @@ export class TXE {
562
459
  contract: call.to,
563
460
  selector: call.selector
564
461
  });
565
- const args = await this.loadFromExecutionCache(argsHash);
462
+ const args = await this.privateLoadFromExecutionCache(argsHash);
566
463
  const initialWitness = toACVMWitness(0, args);
567
464
  const acirExecutionResult = await this.simulator.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
568
465
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
@@ -576,69 +473,20 @@ export class TXE {
576
473
  const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
577
474
  this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
578
475
  const returnHash = await computeVarArgsHash(returnWitness);
579
- this.storeInExecutionCache(returnWitness, returnHash);
476
+ this.privateStoreInExecutionCache(returnWitness, returnHash);
580
477
  return returnHash;
581
478
  } catch (err) {
582
479
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
583
480
  }
584
481
  }
585
- async callPrivateFunction(targetContractAddress, functionSelector, argsHash, sideEffectCounter, isStaticCall) {
586
- this.logger.verbose(`Executing external function ${await this.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
587
- // Store and modify env
588
- const currentContractAddress = this.contractAddress;
589
- const currentMessageSender = this.msgSender;
590
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
591
- this.setMsgSender(this.contractAddress);
592
- this.setContractAddress(targetContractAddress);
593
- this.setFunctionSelector(functionSelector);
594
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
595
- if (!artifact) {
596
- throw new Error(`Artifact not found when calling private function. Contract address: ${targetContractAddress}.`);
597
- }
598
- const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
599
- const acvmCallback = new Oracle(this);
600
- const timer = new Timer();
601
- const acirExecutionResult = await this.simulator.executeUserCircuit(initialWitness, artifact, acvmCallback.toACIRCallback()).catch((err)=>{
602
- err.message = resolveAssertionMessageFromError(err, artifact);
603
- const execError = new ExecutionError(err.message, {
604
- contractAddress: targetContractAddress,
605
- functionSelector
606
- }, extractCallStack(err, artifact.debug), {
607
- cause: err
608
- });
609
- this.logger.debug(`Error executing private function ${targetContractAddress}:${functionSelector}`);
610
- throw createSimulationError(execError);
611
- });
612
- const duration = timer.ms();
613
- const publicInputs = extractPrivateCircuitPublicInputs(artifact, acirExecutionResult.partialWitness);
614
- const initialWitnessSize = witnessMapToFields(initialWitness).length * Fr.SIZE_IN_BYTES;
615
- this.logger.debug(`Ran external function ${targetContractAddress.toString()}:${functionSelector}`, {
616
- circuitName: 'app-circuit',
617
- duration,
618
- eventName: 'circuit-witness-generation',
619
- inputSize: initialWitnessSize,
620
- outputSize: publicInputs.toBuffer().length,
621
- appCircuitName: 'noname'
622
- });
623
- // Apply side effects
624
- const endSideEffectCounter = publicInputs.endSideEffectCounter;
625
- this.sideEffectCounter = endSideEffectCounter.toNumber() + 1;
626
- await this.addPrivateLogs(targetContractAddress, publicInputs.privateLogs.filter((privateLog)=>!privateLog.isEmpty()).map((privateLog)=>privateLog.log));
627
- this.setContractAddress(currentContractAddress);
628
- this.setMsgSender(currentMessageSender);
629
- this.setFunctionSelector(currentFunctionSelector);
630
- return {
631
- endSideEffectCounter,
632
- returnsHash: publicInputs.returnsHash
633
- };
634
- }
635
482
  async getInitialWitness(abi, argsHash, sideEffectCounter, isStaticCall) {
636
483
  const argumentsSize = countArgumentsSize(abi);
637
484
  const args = this.executionCache.getPreimage(argsHash);
638
485
  if (args?.length !== argumentsSize) {
639
486
  throw new Error('Invalid arguments size');
640
487
  }
641
- const privateContextInputs = await this.getPrivateContextInputs(this.blockNumber - 1, this.timestamp - AZTEC_SLOT_DURATION, sideEffectCounter, isStaticCall);
488
+ const historicalBlockNumber = this.blockNumber - 1; // i.e. last
489
+ const privateContextInputs = await this.txeGetPrivateContextInputs(historicalBlockNumber, sideEffectCounter, isStaticCall);
642
490
  const privateContextInputsAsFields = privateContextInputs.toFields();
643
491
  if (privateContextInputsAsFields.length !== PRIVATE_CONTEXT_INPUTS_LENGTH) {
644
492
  throw new Error('Invalid private context inputs size');
@@ -652,161 +500,36 @@ export class TXE {
652
500
  async getDebugFunctionName(address, selector) {
653
501
  return await this.contractDataProvider.getDebugFunctionName(address, selector);
654
502
  }
655
- async executePublicFunction(calldata, msgSender, contractAddress, isStaticCall, isTeardown = false) {
656
- const callRequest = await PublicCallRequest.fromCalldata(msgSender, contractAddress, isStaticCall, calldata);
657
- const executionRequest = new PublicCallRequestWithCalldata(callRequest, calldata);
658
- const db = this.baseFork;
659
- const globalVariables = GlobalVariables.empty();
660
- globalVariables.chainId = new Fr(this.CHAIN_ID);
661
- globalVariables.version = new Fr(this.ROLLUP_VERSION);
662
- globalVariables.blockNumber = this.blockNumber;
663
- globalVariables.timestamp = this.timestamp;
664
- globalVariables.gasFees = new GasFees(1, 1);
665
- let result;
666
- // Checkpoint here so that we can revert merkle ops after simulation.
667
- // See note at revert below.
668
- const checkpoint = await ForkCheckpoint.new(db);
669
- try {
670
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
671
- const simulator = new PublicTxSimulator(this.baseFork, contractsDB, globalVariables, /*doMerkleOperations=*/ false, /*skipFeeEnforcement=*/ false, /*clientInitiatedSimulation=*/ true);
672
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
673
- const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
674
- // When setting up a teardown call, we tell it that
675
- // private execution used Gas(1, 1) so it can compute a tx fee.
676
- const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty();
677
- const tx = createTxForPublicCalls({
678
- nonRevertible: {
679
- nullifiers: [
680
- firstNullifier
681
- ]
682
- }
683
- }, /*setupExecutionRequests=*/ [], /*appExecutionRequests=*/ isTeardown ? [] : [
684
- executionRequest
685
- ], /*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined, /*feePayer=*/ AztecAddress.zero(), gasUsedByPrivate);
686
- result = await simulator.simulate(tx);
687
- } finally{
688
- // NOTE: Don't accept any merkle updates from the AVM since this was just 1 enqueued call
689
- // and the TXE will re-apply all txEffects after entire execution (all enqueued calls)
690
- // complete.
691
- await checkpoint.revert();
692
- // If an error is thrown during the above simulation, this revert is the last
693
- // thing executed and we skip the postprocessing below.
694
- }
695
- const noteHashes = result.avmProvingRequest.inputs.publicInputs.accumulatedData.noteHashes.filter((s)=>!s.isEmpty());
696
- const publicDataWrites = result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicDataWrites.filter((s)=>!s.isEmpty());
697
- // For now, public data writes are the only merkle operations that are readable by later enqueued calls in the TXE.
698
- await this.addPublicDataWrites(publicDataWrites);
699
- this.addUniqueNoteHashesFromPublic(noteHashes);
700
- this.addPublicLogs(result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicLogs.filter((log)=>!log.contractAddress.equals(AztecAddress.ZERO)));
701
- return Promise.resolve(result);
702
- }
703
- async notifyEnqueuedPublicFunctionCall(targetContractAddress, calldataHash, _sideEffectCounter, isStaticCall, isTeardown = false) {
704
- // Store and modify env
705
- const currentContractAddress = this.contractAddress;
706
- const currentMessageSender = this.msgSender;
707
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
708
- const calldata = this.executionCache.getPreimage(calldataHash);
709
- if (!calldata) {
710
- throw new Error('Calldata for enqueued call not found in cache');
711
- }
712
- const functionSelector = FunctionSelector.fromField(calldata[0]);
713
- this.setMsgSender(this.contractAddress);
714
- this.setContractAddress(targetContractAddress);
715
- this.setFunctionSelector(functionSelector);
716
- const executionResult = await this.executePublicFunction(calldata, /* msgSender */ currentContractAddress, targetContractAddress, isStaticCall, isTeardown);
717
- // Poor man's revert handling
718
- if (!executionResult.revertCode.isOK()) {
719
- if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) {
720
- await enrichPublicSimulationError(executionResult.revertReason, this.contractDataProvider, this.logger);
721
- throw new Error(executionResult.revertReason.message);
722
- } else {
723
- throw new Error(`Enqueued public function call reverted: ${executionResult.revertReason}`);
724
- }
725
- }
726
- // Apply side effects
727
- const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
728
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
729
- const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
730
- const nullifiers = sideEffects.nullifiers.filter((s)=>!s.isEmpty()).filter((s)=>!s.equals(firstNullifier));
731
- // For some reason we cannot move this up to 'executePublicFunction'. It gives us an error of trying to modify the same nullifier twice.
732
- this.addSiloedNullifiersFromPublic(nullifiers);
733
- this.setContractAddress(currentContractAddress);
734
- this.setMsgSender(currentMessageSender);
735
- this.setFunctionSelector(currentFunctionSelector);
736
- }
737
- async notifySetPublicTeardownFunctionCall(targetContractAddress, calldataHash, sideEffectCounter, isStaticCall) {
738
- // Definitely not right, in that the teardown should always be last.
739
- // But useful for executing flows.
740
- await this.notifyEnqueuedPublicFunctionCall(targetContractAddress, calldataHash, sideEffectCounter, isStaticCall, /*isTeardown=*/ true);
741
- }
742
- async notifySetMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter) {
743
- await this.noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
744
- }
745
- debugLog(message, fields) {
503
+ utilityDebugLog(message, fields) {
746
504
  this.logger.verbose(`${applyStringFormatting(message, fields)}`, {
747
505
  module: `${this.logger.module}:debug_log`
748
506
  });
749
507
  }
750
- async incrementAppTaggingSecretIndexAsSender(sender, recipient) {
508
+ async privateIncrementAppTaggingSecretIndexAsSender(sender, recipient) {
751
509
  await this.pxeOracleInterface.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient);
752
510
  }
753
- async getIndexedTaggingSecretAsSender(sender, recipient) {
511
+ async utilityGetIndexedTaggingSecretAsSender(sender, recipient) {
754
512
  return await this.pxeOracleInterface.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient);
755
513
  }
756
- async fetchTaggedLogs(pendingTaggedLogArrayBaseSlot) {
514
+ async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot) {
757
515
  await this.pxeOracleInterface.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot);
758
516
  await this.pxeOracleInterface.removeNullifiedNotes(this.contractAddress);
759
517
  return Promise.resolve();
760
518
  }
761
- async validateEnqueuedNotesAndEvents(contractAddress, noteValidationRequestsArrayBaseSlot, eventValidationRequestsArrayBaseSlot) {
519
+ async utilityValidateEnqueuedNotesAndEvents(contractAddress, noteValidationRequestsArrayBaseSlot, eventValidationRequestsArrayBaseSlot) {
762
520
  await this.pxeOracleInterface.validateEnqueuedNotesAndEvents(contractAddress, noteValidationRequestsArrayBaseSlot, eventValidationRequestsArrayBaseSlot);
763
521
  }
764
- async bulkRetrieveLogs(contractAddress, logRetrievalRequestsArrayBaseSlot, logRetrievalResponsesArrayBaseSlot) {
522
+ async utilityBulkRetrieveLogs(contractAddress, logRetrievalRequestsArrayBaseSlot, logRetrievalResponsesArrayBaseSlot) {
765
523
  return await this.pxeOracleInterface.bulkRetrieveLogs(contractAddress, logRetrievalRequestsArrayBaseSlot, logRetrievalResponsesArrayBaseSlot);
766
524
  }
767
- // AVM oracles
768
- async avmOpcodeCall(targetContractAddress, calldata, isStaticCall) {
769
- // Store and modify env
770
- const currentContractAddress = this.contractAddress;
771
- const currentMessageSender = this.msgSender;
772
- this.setMsgSender(this.contractAddress);
773
- this.setContractAddress(targetContractAddress);
774
- const executionResult = await this.executePublicFunction(calldata, /* msgSender */ currentContractAddress, targetContractAddress, isStaticCall);
775
- // Save return/revert data for later.
776
- this.nestedCallReturndata = executionResult.processedPhases[0].returnValues[0].values;
777
- this.nestedCallSuccess = executionResult.revertCode.isOK();
778
- // Apply side effects
779
- if (executionResult.revertCode.isOK()) {
780
- const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
781
- const publicDataWrites = sideEffects.publicDataWrites.filter((s)=>!s.isEmpty());
782
- const noteHashes = sideEffects.noteHashes.filter((s)=>!s.isEmpty());
783
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
784
- const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
785
- const nullifiers = sideEffects.nullifiers.filter((s)=>!s.isEmpty()).filter((s)=>!s.equals(firstNullifier));
786
- await this.addPublicDataWrites(publicDataWrites);
787
- this.addUniqueNoteHashesFromPublic(noteHashes);
788
- this.addSiloedNullifiersFromPublic(nullifiers);
789
- }
790
- this.setContractAddress(currentContractAddress);
791
- this.setMsgSender(currentMessageSender);
792
- return executionResult;
793
- }
794
- avmOpcodeSuccessCopy() {
795
- return this.nestedCallSuccess;
796
- }
797
- avmOpcodeReturndataSize() {
798
- return this.nestedCallReturndata.length;
799
- }
800
- avmOpcodeReturndataCopy(rdOffset, copySize) {
801
- return this.nestedCallReturndata.slice(rdOffset, rdOffset + copySize);
802
- }
803
525
  async avmOpcodeNullifierExists(innerNullifier, targetAddress) {
804
526
  const nullifier = await siloNullifier(targetAddress, innerNullifier);
805
527
  const db = this.baseFork;
806
- const index = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
528
+ const treeIndex = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
807
529
  nullifier.toBuffer()
808
530
  ]))[0];
809
- return index !== undefined;
531
+ const transientIndex = this.siloedNullifiersFromPublic.find((n)=>n.equals(nullifier));
532
+ return treeIndex !== undefined || transientIndex !== undefined;
810
533
  }
811
534
  async avmOpcodeEmitNullifier(nullifier) {
812
535
  const siloedNullifier = await siloNullifier(this.contractAddress, nullifier);
@@ -832,50 +555,57 @@ export class TXE {
832
555
  const preimage = await this.baseFork.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
833
556
  return preimage.leaf.value;
834
557
  }
835
- storeCapsule(contractAddress, slot, capsule) {
558
+ utilityStoreCapsule(contractAddress, slot, capsule) {
836
559
  if (!contractAddress.equals(this.contractAddress)) {
837
560
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
838
561
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
839
562
  }
840
563
  return this.pxeOracleInterface.storeCapsule(this.contractAddress, slot, capsule);
841
564
  }
842
- loadCapsule(contractAddress, slot) {
565
+ utilityLoadCapsule(contractAddress, slot) {
843
566
  if (!contractAddress.equals(this.contractAddress)) {
844
567
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
845
568
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
846
569
  }
847
570
  return this.pxeOracleInterface.loadCapsule(this.contractAddress, slot);
848
571
  }
849
- deleteCapsule(contractAddress, slot) {
572
+ utilityDeleteCapsule(contractAddress, slot) {
850
573
  if (!contractAddress.equals(this.contractAddress)) {
851
574
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
852
575
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
853
576
  }
854
577
  return this.pxeOracleInterface.deleteCapsule(this.contractAddress, slot);
855
578
  }
856
- copyCapsule(contractAddress, srcSlot, dstSlot, numEntries) {
579
+ utilityCopyCapsule(contractAddress, srcSlot, dstSlot, numEntries) {
857
580
  if (!contractAddress.equals(this.contractAddress)) {
858
581
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
859
582
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
860
583
  }
861
584
  return this.pxeOracleInterface.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries);
862
585
  }
863
- aes128Decrypt(ciphertext, iv, symKey) {
586
+ utilityAes128Decrypt(ciphertext, iv, symKey) {
864
587
  const aes128 = new Aes128();
865
588
  return aes128.decryptBufferCBC(ciphertext, iv, symKey);
866
589
  }
867
- getSharedSecret(address, ephPk) {
590
+ utilityGetSharedSecret(address, ephPk) {
868
591
  return this.pxeOracleInterface.getSharedSecret(address, ephPk);
869
592
  }
870
- emitOffchainEffect(_data) {
871
- // Offchain effects are discarded in TXE tests.
593
+ privateGetSenderForTags() {
594
+ return Promise.resolve(this.senderForTags);
595
+ }
596
+ privateSetSenderForTags(senderForTags) {
597
+ this.senderForTags = senderForTags;
872
598
  return Promise.resolve();
873
599
  }
874
- async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
600
+ async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
875
601
  this.logger.verbose(`Executing external function ${await this.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
876
602
  const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
877
603
  if (artifact === undefined) {
878
- throw new Error('Function Artifact does not exist');
604
+ if (functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))) {
605
+ throw new Error('Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.');
606
+ } else {
607
+ throw new Error('Function Artifact does not exist');
608
+ }
879
609
  }
880
610
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
881
611
  const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
@@ -884,8 +614,12 @@ export class TXE {
884
614
  const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
885
615
  const blockHeader = await this.pxeOracleInterface.getBlockHeader();
886
616
  const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
887
- const context = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ [], /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create(), noteCache, this.pxeOracleInterface, this.simulator, 0, 1);
888
- context.storeInExecutionCache(args, argsHash);
617
+ // TODO(benesjan): Fix stale 'context' name.
618
+ const context = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ Array.from(this.authwits.values()), /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create(), noteCache, this.pxeOracleInterface, this.simulator, 0, 1, undefined, undefined, /**
619
+ * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
620
+ * contract would perform, including setting senderForTags.
621
+ */ from);
622
+ context.privateStoreInExecutionCache(args, argsHash);
889
623
  // 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.
890
624
  let result;
891
625
  let executionResult;
@@ -895,12 +629,11 @@ export class TXE {
895
629
  const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
896
630
  const publicCallRequests = collectNested([
897
631
  executionResult
898
- ], (r)=>[
899
- ...r.publicInputs.publicCallRequests.map((r)=>r.inner),
632
+ ], (r)=>r.publicInputs.publicCallRequests.getActiveItems().map((r)=>r.inner).concat(r.publicInputs.publicTeardownCallRequest.isEmpty() ? [] : [
900
633
  r.publicInputs.publicTeardownCallRequest
901
- ]).filter((r)=>!r.isEmpty());
634
+ ]));
902
635
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
903
- const calldata = await context.loadFromExecutionCache(r.calldataHash);
636
+ const calldata = await context.privateLoadFromExecutionCache(r.calldataHash);
904
637
  return new HashedValues(calldata, r.calldataHash);
905
638
  }));
906
639
  result = new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
@@ -912,7 +645,7 @@ export class TXE {
912
645
  // This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
913
646
  // Investigate whether it is faster to do this or return from the oracle directly.
914
647
  const returnValuesHash = await computeVarArgsHash(returnValues);
915
- this.storeInExecutionCache(returnValues, returnValuesHash);
648
+ this.privateStoreInExecutionCache(returnValues, returnValuesHash);
916
649
  }
917
650
  // According to the protocol rules, the nonce generator for the note hashes
918
651
  // can either be the first nullifier in the tx or the hash of the initial tx request
@@ -922,12 +655,19 @@ export class TXE {
922
655
  const globals = makeGlobalVariables();
923
656
  globals.blockNumber = this.blockNumber;
924
657
  globals.timestamp = this.timestamp;
658
+ globals.chainId = new Fr(this.CHAIN_ID);
659
+ globals.version = new Fr(this.ROLLUP_VERSION);
925
660
  globals.gasFees = GasFees.empty();
926
661
  const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
927
662
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(this.baseFork);
928
663
  const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
929
664
  const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
930
- const tx = new Tx(publicInputs, ClientIvcProof.empty(), [], result.publicFunctionCalldata);
665
+ const tx = await Tx.create({
666
+ data: publicInputs,
667
+ clientIvcProof: ClientIvcProof.empty(),
668
+ contractClassLogFields: [],
669
+ publicFunctionCalldata: result.publicFunctionCalldata
670
+ });
931
671
  let checkpoint;
932
672
  if (isStaticCall) {
933
673
  checkpoint = await ForkCheckpoint.new(this.baseFork);
@@ -935,27 +675,33 @@ export class TXE {
935
675
  const results = await processor.process([
936
676
  tx
937
677
  ]);
938
- const processedTxs = results[0];
678
+ const [processedTx] = results[0];
939
679
  const failedTxs = results[1];
940
680
  if (failedTxs.length !== 0) {
941
- throw new Error('Public execution has failed');
681
+ throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
682
+ } else if (!processedTx.revertCode.isOK()) {
683
+ if (processedTx.revertReason) {
684
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
685
+ throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
686
+ } else {
687
+ throw new Error('Contract execution has reverted');
688
+ }
942
689
  }
943
690
  if (isStaticCall) {
944
691
  await checkpoint.revert();
945
- const txRequestHash = this.getTxRequestHash();
946
692
  return {
947
693
  endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
948
694
  returnsHash: result.entrypoint.publicInputs.returnsHash,
949
- txHash: txRequestHash
695
+ txHash: tx.getTxHash()
950
696
  };
951
697
  }
952
698
  const fork = this.baseFork;
953
699
  const txEffect = TxEffect.empty();
954
- txEffect.noteHashes = processedTxs[0].txEffect.noteHashes;
955
- txEffect.nullifiers = processedTxs[0].txEffect.nullifiers;
956
- txEffect.privateLogs = processedTxs[0].txEffect.privateLogs;
957
- txEffect.publicLogs = processedTxs[0].txEffect.publicLogs;
958
- txEffect.publicDataWrites = processedTxs[0].txEffect.publicDataWrites;
700
+ txEffect.noteHashes = processedTx.txEffect.noteHashes;
701
+ txEffect.nullifiers = processedTx.txEffect.nullifiers;
702
+ txEffect.privateLogs = processedTx.txEffect.privateLogs;
703
+ txEffect.publicLogs = processedTx.txEffect.publicLogs;
704
+ txEffect.publicDataWrites = processedTx.txEffect.publicDataWrites;
959
705
  txEffect.txHash = new TxHash(new Fr(this.blockNumber));
960
706
  const body = new Body([
961
707
  txEffect
@@ -970,53 +716,55 @@ export class TXE {
970
716
  l2Block.header = header;
971
717
  await fork.updateArchive(l2Block.header);
972
718
  await this.stateMachine.handleL2Block(l2Block);
973
- const txRequestHash = this.getTxRequestHash();
974
719
  this.setBlockNumber(this.blockNumber + 1);
975
- this.advanceTimestampBy(AZTEC_SLOT_DURATION);
976
720
  return {
977
721
  endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
978
722
  returnsHash: result.entrypoint.publicInputs.returnsHash,
979
- txHash: txRequestHash
723
+ txHash: tx.getTxHash()
980
724
  };
981
725
  }
982
- async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
726
+ async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
983
727
  this.logger.verbose(`Executing public function ${await this.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
984
728
  const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
985
729
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
986
730
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
987
731
  const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
988
732
  const blockHeader = await this.pxeOracleInterface.getBlockHeader();
989
- const uniqueNoteHashes = [];
990
- const taggedPrivateLogs = [];
991
- const nullifiers = !isStaticCall ? [
992
- this.getTxRequestHash()
993
- ] : [];
994
- const l2ToL1Messages = [];
995
- const contractClassLogsHashes = [];
996
733
  const calldataHash = await computeCalldataHash(calldata);
997
734
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
998
- const publicCallRequest = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
999
- const publicCallRequests = [
1000
- publicCallRequest
1001
- ];
1002
735
  const globals = makeGlobalVariables();
1003
736
  globals.blockNumber = this.blockNumber;
1004
737
  globals.timestamp = this.timestamp;
738
+ globals.chainId = new Fr(this.CHAIN_ID);
739
+ globals.version = new Fr(this.ROLLUP_VERSION);
1005
740
  globals.gasFees = GasFees.empty();
1006
741
  const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
1007
742
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(this.baseFork);
1008
743
  const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
1009
744
  const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
745
+ // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
746
+ // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
747
+ // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
748
+ // unique.
749
+ const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
750
+ if (!isStaticCall) {
751
+ nonRevertibleAccumulatedData.nullifiers[0] = this.getTxRequestHash();
752
+ }
753
+ // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
754
+ // may require producing reverts.
755
+ const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
756
+ revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
757
+ const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
1010
758
  const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
1011
- const accumulatedDataForPublic = new PrivateToPublicAccumulatedData(padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX), padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX), padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX), padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX), padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX), padArrayEnd(publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX));
1012
- const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(// nonrevertible
1013
- PrivateToPublicAccumulatedData.empty(), // revertible
1014
- // We are using revertible (app phase) because only the app-phase returns are exposed.
1015
- accumulatedDataForPublic, PublicCallRequest.empty());
1016
- const txData = new PrivateKernelTailCircuitPublicInputs(constantData, RollupValidationRequests.empty(), /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), inputsForPublic, undefined);
1017
- const tx = new Tx(txData, ClientIvcProof.empty(), [], [
1018
- calldataHashedValues
1019
- ]);
759
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
760
+ const tx = await Tx.create({
761
+ data: txData,
762
+ clientIvcProof: ClientIvcProof.empty(),
763
+ contractClassLogFields: [],
764
+ publicFunctionCalldata: [
765
+ calldataHashedValues
766
+ ]
767
+ });
1020
768
  let checkpoint;
1021
769
  if (isStaticCall) {
1022
770
  checkpoint = await ForkCheckpoint.new(this.baseFork);
@@ -1024,10 +772,17 @@ export class TXE {
1024
772
  const results = await processor.process([
1025
773
  tx
1026
774
  ]);
1027
- const processedTxs = results[0];
775
+ const [processedTx] = results[0];
1028
776
  const failedTxs = results[1];
1029
- if (failedTxs.length !== 0 || !processedTxs[0].revertCode.isOK()) {
1030
- throw new Error('Public execution has failed');
777
+ if (failedTxs.length !== 0) {
778
+ throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
779
+ } else if (!processedTx.revertCode.isOK()) {
780
+ if (processedTx.revertReason) {
781
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
782
+ throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
783
+ } else {
784
+ throw new Error('Contract execution has reverted');
785
+ }
1031
786
  }
1032
787
  const returnValues = results[3][0].values;
1033
788
  let returnValuesHash;
@@ -1035,23 +790,22 @@ export class TXE {
1035
790
  // This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
1036
791
  // Investigate whether it is faster to do this or return from the oracle directly.
1037
792
  returnValuesHash = await computeVarArgsHash(returnValues);
1038
- this.storeInExecutionCache(returnValues, returnValuesHash);
793
+ this.privateStoreInExecutionCache(returnValues, returnValuesHash);
1039
794
  }
1040
795
  if (isStaticCall) {
1041
796
  await checkpoint.revert();
1042
- const txRequestHash = this.getTxRequestHash();
1043
797
  return {
1044
798
  returnsHash: returnValuesHash ?? Fr.ZERO,
1045
- txHash: txRequestHash
799
+ txHash: tx.getTxHash()
1046
800
  };
1047
801
  }
1048
802
  const fork = this.baseFork;
1049
803
  const txEffect = TxEffect.empty();
1050
- txEffect.noteHashes = processedTxs[0].txEffect.noteHashes;
1051
- txEffect.nullifiers = processedTxs[0].txEffect.nullifiers;
1052
- txEffect.privateLogs = taggedPrivateLogs;
1053
- txEffect.publicLogs = processedTxs[0].txEffect.publicLogs;
1054
- txEffect.publicDataWrites = processedTxs[0].txEffect.publicDataWrites;
804
+ txEffect.noteHashes = processedTx.txEffect.noteHashes;
805
+ txEffect.nullifiers = processedTx.txEffect.nullifiers;
806
+ txEffect.privateLogs = processedTx.txEffect.privateLogs;
807
+ txEffect.publicLogs = processedTx.txEffect.publicLogs;
808
+ txEffect.publicDataWrites = processedTx.txEffect.publicDataWrites;
1055
809
  txEffect.txHash = new TxHash(new Fr(this.blockNumber));
1056
810
  const body = new Body([
1057
811
  txEffect
@@ -1066,12 +820,17 @@ export class TXE {
1066
820
  l2Block.header = header;
1067
821
  await fork.updateArchive(l2Block.header);
1068
822
  await this.stateMachine.handleL2Block(l2Block);
1069
- const txRequestHash = this.getTxRequestHash();
1070
823
  this.setBlockNumber(this.blockNumber + 1);
1071
- this.advanceTimestampBy(AZTEC_SLOT_DURATION);
1072
824
  return {
1073
825
  returnsHash: returnValuesHash ?? Fr.ZERO,
1074
- txHash: txRequestHash
826
+ txHash: tx.getTxHash()
1075
827
  };
1076
828
  }
829
+ async getBlockTimestamp(blockNumber) {
830
+ const blockHeader = await this.stateMachine.archiver.getBlockHeader(blockNumber);
831
+ if (!blockHeader) {
832
+ throw new Error(`Requested timestamp for block ${blockNumber}, which does not exist`);
833
+ }
834
+ return blockHeader.globalVariables.timestamp;
835
+ }
1077
836
  }