@aztec/txe 0.0.1-commit.1142ef1 → 0.0.1-commit.11bf3dd6e

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.
Files changed (72) hide show
  1. package/dest/constants.d.ts +1 -2
  2. package/dest/constants.d.ts.map +1 -1
  3. package/dest/constants.js +0 -1
  4. package/dest/index.d.ts +1 -1
  5. package/dest/index.d.ts.map +1 -1
  6. package/dest/index.js +88 -54
  7. package/dest/oracle/interfaces.d.ts +29 -28
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +13 -13
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +16 -16
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +28 -22
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +165 -71
  15. package/dest/rpc_translator.d.ts +125 -81
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +426 -179
  18. package/dest/state_machine/archiver.d.ts +20 -69
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +36 -179
  21. package/dest/state_machine/dummy_p2p_client.d.ts +18 -13
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +33 -18
  24. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  25. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  26. package/dest/state_machine/global_variable_builder.js +9 -3
  27. package/dest/state_machine/index.d.ts +7 -5
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +40 -13
  30. package/dest/state_machine/mock_epoch_cache.d.ts +25 -8
  31. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  32. package/dest/state_machine/mock_epoch_cache.js +46 -9
  33. package/dest/state_machine/synchronizer.d.ts +6 -6
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/state_machine/synchronizer.js +3 -3
  36. package/dest/txe_session.d.ts +12 -6
  37. package/dest/txe_session.d.ts.map +1 -1
  38. package/dest/txe_session.js +115 -28
  39. package/dest/util/encoding.d.ts +88 -18
  40. package/dest/util/encoding.d.ts.map +1 -1
  41. package/dest/util/encoding.js +4 -0
  42. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  43. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  44. package/dest/util/txe_public_contract_data_source.js +6 -25
  45. package/dest/utils/block_creation.d.ts +4 -4
  46. package/dest/utils/block_creation.d.ts.map +1 -1
  47. package/dest/utils/block_creation.js +18 -4
  48. package/dest/utils/tx_effect_creation.d.ts +2 -3
  49. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  50. package/dest/utils/tx_effect_creation.js +3 -6
  51. package/package.json +16 -16
  52. package/src/constants.ts +0 -1
  53. package/src/index.ts +89 -52
  54. package/src/oracle/interfaces.ts +32 -31
  55. package/src/oracle/txe_oracle_public_context.ts +16 -18
  56. package/src/oracle/txe_oracle_top_level_context.ts +208 -123
  57. package/src/rpc_translator.ts +493 -204
  58. package/src/state_machine/archiver.ts +38 -234
  59. package/src/state_machine/dummy_p2p_client.ts +46 -24
  60. package/src/state_machine/global_variable_builder.ts +18 -3
  61. package/src/state_machine/index.ts +56 -12
  62. package/src/state_machine/mock_epoch_cache.ts +57 -14
  63. package/src/state_machine/synchronizer.ts +5 -5
  64. package/src/txe_session.ts +132 -88
  65. package/src/util/encoding.ts +5 -0
  66. package/src/util/txe_public_contract_data_source.ts +10 -38
  67. package/src/utils/block_creation.ts +19 -16
  68. package/src/utils/tx_effect_creation.ts +3 -11
  69. package/dest/util/txe_contract_store.d.ts +0 -12
  70. package/dest/util/txe_contract_store.d.ts.map +0 -1
  71. package/dest/util/txe_contract_store.js +0 -22
  72. package/src/util/txe_contract_store.ts +0 -36
@@ -1,9 +1,7 @@
1
1
  import {
2
2
  CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
3
- DEFAULT_DA_GAS_LIMIT,
4
- DEFAULT_L2_GAS_LIMIT,
5
- DEFAULT_TEARDOWN_DA_GAS_LIMIT,
6
- DEFAULT_TEARDOWN_L2_GAS_LIMIT,
3
+ MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT,
4
+ MAX_PROCESSABLE_L2_GAS,
7
5
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
8
6
  } from '@aztec/constants';
9
7
  import { BlockNumber } from '@aztec/foundation/branded-types';
@@ -14,9 +12,12 @@ import { TestDateProvider } from '@aztec/foundation/timer';
14
12
  import type { KeyStore } from '@aztec/key-store';
15
13
  import {
16
14
  AddressStore,
15
+ CapsuleService,
17
16
  CapsuleStore,
17
+ type ContractStore,
18
+ type ContractSyncService,
18
19
  NoteStore,
19
- ORACLE_VERSION,
20
+ ORACLE_VERSION_MAJOR,
20
21
  PrivateEventStore,
21
22
  RecipientTaggingStore,
22
23
  SenderAddressBookStore,
@@ -54,7 +55,13 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
54
55
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
55
56
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
56
57
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
57
- import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
58
+ import {
59
+ FALLBACK_TEARDOWN_DA_GAS_LIMIT,
60
+ FALLBACK_TEARDOWN_L2_GAS_LIMIT,
61
+ Gas,
62
+ GasFees,
63
+ GasSettings,
64
+ } from '@aztec/stdlib/gas';
58
65
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
59
66
  import {
60
67
  PartialPrivateTailPublicInputsForPublic,
@@ -80,10 +87,9 @@ import {
80
87
  import type { UInt64 } from '@aztec/stdlib/types';
81
88
  import { ForkCheckpoint } from '@aztec/world-state';
82
89
 
83
- import { DEFAULT_ADDRESS, TXE_JOB_ID } from '../constants.js';
90
+ import { DEFAULT_ADDRESS } from '../constants.js';
84
91
  import type { TXEStateMachine } from '../state_machine/index.js';
85
92
  import type { TXEAccountStore } from '../util/txe_account_store.js';
86
- import type { TXEContractStore } from '../util/txe_contract_store.js';
87
93
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
88
94
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
89
95
  import type { ITxeExecutionOracle } from './interfaces.js';
@@ -96,7 +102,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
96
102
 
97
103
  constructor(
98
104
  private stateMachine: TXEStateMachine,
99
- private contractStore: TXEContractStore,
105
+ private contractStore: ContractStore,
100
106
  private noteStore: NoteStore,
101
107
  private keyStore: KeyStore,
102
108
  private addressStore: AddressStore,
@@ -110,53 +116,68 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
110
116
  private version: Fr,
111
117
  private chainId: Fr,
112
118
  private authwits: Map<string, AuthWitness>,
119
+ private readonly contractSyncService: ContractSyncService,
113
120
  ) {
114
121
  this.logger = createLogger('txe:top_level_context');
115
122
  this.logger.debug('Entering Top Level Context');
116
123
  }
117
124
 
118
- utilityAssertCompatibleOracleVersion(version: number): void {
119
- if (version !== ORACLE_VERSION) {
125
+ private contractOracleVersion: { major: number; minor: number } | undefined;
126
+
127
+ assertCompatibleOracleVersion(major: number, minor: number): void {
128
+ if (major !== ORACLE_VERSION_MAJOR) {
129
+ const hint =
130
+ major > ORACLE_VERSION_MAJOR
131
+ ? 'The contract was compiled with a newer version of Aztec.nr than this aztec cli version supports. Upgrade your aztec cli version to a compatible version.'
132
+ : 'The contract was compiled with an older version of Aztec.nr than this aztec cli version supports. Recompile the contract with a compatible version of Aztec.nr.';
120
133
  throw new Error(
121
- `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
134
+ `Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
122
135
  );
123
136
  }
137
+ this.contractOracleVersion = { major, minor };
138
+ }
139
+
140
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
141
+ nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
142
+ return this.contractOracleVersion;
124
143
  }
125
144
 
126
145
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
127
146
  // setup.
128
- utilityGetRandomField(): Fr {
147
+ getRandomField(): Fr {
129
148
  return Fr.random();
130
149
  }
131
150
 
132
151
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
133
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
152
+ log(level: number, message: string, fields: Fr[]): Promise<void> {
134
153
  if (!LogLevels[level]) {
135
- throw new Error(`Invalid debug log level: ${level}`);
154
+ throw new Error(`Invalid log level: ${level}`);
136
155
  }
137
156
  const levelName = LogLevels[level];
138
157
 
139
158
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
159
+ return Promise.resolve();
140
160
  }
141
161
 
142
- txeGetDefaultAddress(): AztecAddress {
162
+ getDefaultAddress(): AztecAddress {
143
163
  return DEFAULT_ADDRESS;
144
164
  }
145
165
 
146
- async txeGetNextBlockNumber(): Promise<BlockNumber> {
166
+ async getNextBlockNumber(): Promise<BlockNumber> {
147
167
  return BlockNumber((await this.getLastBlockNumber()) + 1);
148
168
  }
149
169
 
150
- txeGetNextBlockTimestamp(): Promise<bigint> {
170
+ getNextBlockTimestamp(): Promise<bigint> {
151
171
  return Promise.resolve(this.nextBlockTimestamp);
152
172
  }
153
173
 
154
- async txeGetLastBlockTimestamp() {
174
+ async getLastBlockTimestamp() {
155
175
  return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
156
176
  }
157
177
 
158
- async txeGetLastTxEffects() {
159
- const block = await this.stateMachine.archiver.getL2Block('latest');
178
+ async getLastTxEffects() {
179
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
180
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
160
181
 
161
182
  if (block!.body.txEffects.length != 1) {
162
183
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -168,7 +189,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
168
189
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
169
190
  }
170
191
 
171
- async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
192
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
193
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
194
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
195
+ return;
196
+ }
197
+
198
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
199
+ await this.stateMachine.contractSyncService.ensureContractSynced(
200
+ contractAddress,
201
+ null,
202
+ async (call, execScopes) => {
203
+ await this.executeUtilityCall(call, execScopes, jobId);
204
+ },
205
+ blockHeader,
206
+ jobId,
207
+ [scope],
208
+ );
209
+ }
210
+
211
+ async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
172
212
  return (
173
213
  await this.privateEventStore.getPrivateEvents(selector, {
174
214
  contractAddress,
@@ -179,7 +219,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
179
219
  ).map(e => e.packedEvent);
180
220
  }
181
221
 
182
- async txeAdvanceBlocksBy(blocks: number) {
222
+ async advanceBlocksBy(blocks: number) {
183
223
  this.logger.debug(`time traveling ${blocks} blocks`);
184
224
 
185
225
  for (let i = 0; i < blocks; i++) {
@@ -187,12 +227,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
187
227
  }
188
228
  }
189
229
 
190
- txeAdvanceTimestampBy(duration: UInt64) {
230
+ advanceTimestampBy(duration: UInt64) {
191
231
  this.logger.debug(`time traveling ${duration} seconds`);
192
232
  this.nextBlockTimestamp += duration;
193
233
  }
194
234
 
195
- async txeDeploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
235
+ async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
196
236
  // Emit deployment nullifier
197
237
  await this.mineBlock({
198
238
  nullifiers: [
@@ -204,20 +244,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
204
244
  });
205
245
 
206
246
  if (!secret.equals(Fr.ZERO)) {
207
- await this.txeAddAccount(artifact, instance, secret);
247
+ await this.addAccount(artifact, instance, secret);
208
248
  } else {
209
249
  await this.contractStore.addContractInstance(instance);
210
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
250
+ await this.contractStore.addContractArtifact(artifact);
211
251
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
212
252
  }
213
253
  }
214
254
 
215
- async txeAddAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
255
+ async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
216
256
  const partialAddress = await computePartialAddress(instance);
217
257
 
218
258
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
219
259
  await this.contractStore.addContractInstance(instance);
220
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
260
+ await this.contractStore.addContractArtifact(artifact);
221
261
 
222
262
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
223
263
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -227,7 +267,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
227
267
  return completeAddress;
228
268
  }
229
269
 
230
- async txeCreateAccount(secret: Fr) {
270
+ async createAccount(secret: Fr) {
231
271
  // This is a foot gun !
232
272
  const completeAddress = await this.keyStore.addAccount(secret, secret);
233
273
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -237,7 +277,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
237
277
  return completeAddress;
238
278
  }
239
279
 
240
- async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
280
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
241
281
  const account = await this.accountStore.getAccount(address);
242
282
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
243
283
 
@@ -250,7 +290,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
250
290
  }
251
291
 
252
292
  async mineBlock(options: { nullifiers?: Fr[] } = {}) {
253
- const blockNumber = await this.txeGetNextBlockNumber();
293
+ const blockNumber = await this.getNextBlockNumber();
254
294
 
255
295
  const txEffect = TxEffect.empty();
256
296
  txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
@@ -274,13 +314,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
274
314
  await this.stateMachine.handleL2Block(block);
275
315
  }
276
316
 
277
- async txePrivateCallNewFlow(
317
+ async privateCallNewFlow(
278
318
  from: AztecAddress,
279
319
  targetContractAddress: AztecAddress = AztecAddress.zero(),
280
320
  functionSelector: FunctionSelector = FunctionSelector.empty(),
281
321
  args: Fr[],
282
322
  argsHash: Fr = Fr.zero(),
283
323
  isStaticCall: boolean = false,
324
+ jobId: string,
284
325
  ) {
285
326
  this.logger.verbose(
286
327
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -294,68 +335,79 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
294
335
  throw new Error(message);
295
336
  }
296
337
 
338
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
339
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
340
+ const effectiveScopes = from.isZero() ? [] : [from];
341
+
297
342
  // Sync notes before executing private function to discover notes from previous transactions
298
- const utilityExecutor = async (call: FunctionCall) => {
299
- await this.executeUtilityCall(call);
343
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
344
+ await this.executeUtilityCall(call, execScopes, jobId);
300
345
  };
301
346
 
302
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
347
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
348
+ await this.stateMachine.contractSyncService.ensureContractSynced(
349
+ targetContractAddress,
350
+ functionSelector,
351
+ utilityExecutor,
352
+ blockHeader,
353
+ jobId,
354
+ effectiveScopes,
355
+ );
303
356
 
304
- const blockNumber = await this.txeGetNextBlockNumber();
357
+ const blockNumber = await this.getNextBlockNumber();
305
358
 
306
359
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
307
360
 
308
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
309
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
361
+ const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
362
+ const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
310
363
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
311
364
 
312
365
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
313
366
 
314
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
315
-
316
367
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
317
368
  const noteCache = new ExecutionNoteCache(protocolNullifier);
369
+ // In production, the account contract sets the min revertible counter before calling the app function.
370
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
371
+ // marking all side effects as revertible.
372
+ const minRevertibleSideEffectCounter = 1;
373
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
318
374
  const taggingIndexCache = new ExecutionTaggingIndexCache();
319
375
 
320
376
  const simulator = new WASMSimulator();
321
377
 
322
- const privateExecutionOracle = new PrivateExecutionOracle(
378
+ const privateExecutionOracle = new PrivateExecutionOracle({
323
379
  argsHash,
324
380
  txContext,
325
381
  callContext,
326
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
327
- blockHeader,
382
+ anchorBlockHeader: blockHeader,
328
383
  utilityExecutor,
329
- /** List of transient auth witnesses to be used during this simulation */
330
- Array.from(this.authwits.values()),
331
- /** List of transient auth witnesses to be used during this simulation */
332
- [],
333
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
384
+ authWitnesses: Array.from(this.authwits.values()),
385
+ capsules: [],
386
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
334
387
  noteCache,
335
388
  taggingIndexCache,
336
- this.contractStore,
337
- this.noteStore,
338
- this.keyStore,
339
- this.addressStore,
340
- this.stateMachine.node,
341
- this.stateMachine.anchorBlockStore,
342
- this.senderTaggingStore,
343
- this.recipientTaggingStore,
344
- this.senderAddressBookStore,
345
- this.capsuleStore,
346
- this.privateEventStore,
347
- TXE_JOB_ID,
348
- 0,
349
- 1,
350
- undefined, // log
351
- undefined, // scopes
352
- /**
353
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
354
- * contract would perform, including setting senderForTags.
355
- */
356
- from,
389
+ contractStore: this.contractStore,
390
+ noteStore: this.noteStore,
391
+ keyStore: this.keyStore,
392
+ addressStore: this.addressStore,
393
+ aztecNode: this.stateMachine.node,
394
+ senderTaggingStore: this.senderTaggingStore,
395
+ recipientTaggingStore: this.recipientTaggingStore,
396
+ senderAddressBookStore: this.senderAddressBookStore,
397
+ capsuleService: new CapsuleService(this.capsuleStore, effectiveScopes),
398
+ privateEventStore: this.privateEventStore,
399
+ contractSyncService: this.stateMachine.contractSyncService,
400
+ jobId,
401
+ totalPublicCalldataCount: 0,
402
+ sideEffectCounter: minRevertibleSideEffectCounter,
403
+ scopes: effectiveScopes,
404
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
405
+ // contract would perform, including setting senderForTags.
406
+ senderForTags: from,
357
407
  simulator,
358
- );
408
+ messageContextService: this.stateMachine.messageContextService,
409
+ l2TipsStore: this.stateMachine.node,
410
+ });
359
411
 
360
412
  // 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.
361
413
  let result: PrivateExecutionResult;
@@ -377,24 +429,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
377
429
  );
378
430
  const publicFunctionsCalldata = await Promise.all(
379
431
  publicCallRequests.map(async r => {
380
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
432
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
381
433
  return new HashedValues(calldata, r.calldataHash);
382
434
  }),
383
435
  );
384
436
 
385
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
386
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
387
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
388
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
437
+ noteCache.finish();
438
+ const nonceGenerator = noteCache.getNonceGenerator();
439
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
389
440
  } catch (err) {
390
441
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
391
442
  }
392
443
 
393
- // According to the protocol rules, the nonce generator for the note hashes
394
- // can either be the first nullifier in the tx or the hash of the initial tx request
395
- // if there are none.
396
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
397
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractStore);
444
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
445
+ // the nonce generator for the note hashes.
446
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
447
+ const { publicInputs } = await generateSimulatedProvingResult(
448
+ result,
449
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
450
+ this.stateMachine.node,
451
+ minRevertibleSideEffectCounter,
452
+ );
398
453
 
399
454
  const globals = makeGlobalVariables();
400
455
  globals.blockNumber = blockNumber;
@@ -405,7 +460,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
405
460
 
406
461
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
407
462
 
408
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
463
+ const bindings = this.logger.getBindings();
464
+ const contractsDB = new PublicContractsDB(
465
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
466
+ bindings,
467
+ );
409
468
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
410
469
  const config = PublicSimulatorConfig.from({
411
470
  skipFeeEnforcement: true,
@@ -418,8 +477,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
418
477
  globals,
419
478
  guardedMerkleTrees,
420
479
  contractsDB,
421
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
480
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
422
481
  new TestDateProvider(),
482
+ undefined,
483
+ createLogger('simulator:public-processor', bindings),
423
484
  );
424
485
 
425
486
  const tx = await Tx.create({
@@ -482,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
482
543
  return executionResult.returnValues ?? [];
483
544
  }
484
545
 
485
- async txePublicCallNewFlow(
546
+ async publicCallNewFlow(
486
547
  from: AztecAddress,
487
548
  targetContractAddress: AztecAddress,
488
549
  calldata: Fr[],
@@ -492,11 +553,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
492
553
  `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
493
554
  );
494
555
 
495
- const blockNumber = await this.txeGetNextBlockNumber();
556
+ const blockNumber = await this.getNextBlockNumber();
496
557
 
497
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
558
+ const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
498
559
 
499
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
560
+ const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
500
561
 
501
562
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
502
563
 
@@ -516,7 +577,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
516
577
 
517
578
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
518
579
 
519
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
580
+ const bindings2 = this.logger.getBindings();
581
+ const contractsDB = new PublicContractsDB(
582
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
583
+ bindings2,
584
+ );
520
585
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
521
586
  const config = PublicSimulatorConfig.from({
522
587
  skipFeeEnforcement: true,
@@ -525,8 +590,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
525
590
  collectStatistics: false,
526
591
  collectCallMetadata: true,
527
592
  });
528
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
529
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
593
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
594
+ const processor = new PublicProcessor(
595
+ globals,
596
+ guardedMerkleTrees,
597
+ contractsDB,
598
+ simulator,
599
+ new TestDateProvider(),
600
+ undefined,
601
+ createLogger('simulator:public-processor', bindings2),
602
+ );
530
603
 
531
604
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
532
605
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -557,7 +630,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
557
630
  constantData,
558
631
  /*gasUsed=*/ new Gas(0, 0),
559
632
  /*feePayer=*/ AztecAddress.zero(),
560
- /*includeByTimestamp=*/ 0n,
633
+ /*expirationTimestamp=*/ 0n,
561
634
  inputsForPublic,
562
635
  undefined,
563
636
  );
@@ -625,10 +698,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
625
698
  return returnValues ?? [];
626
699
  }
627
700
 
628
- async txeSimulateUtilityFunction(
701
+ async executeUtilityFunction(
629
702
  targetContractAddress: AztecAddress,
630
703
  functionSelector: FunctionSelector,
631
704
  args: Fr[],
705
+ jobId: string,
632
706
  ) {
633
707
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
634
708
  if (!artifact) {
@@ -636,25 +710,33 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
636
710
  }
637
711
 
638
712
  // Sync notes before executing utility function to discover notes from previous transactions
639
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async call => {
640
- await this.executeUtilityCall(call);
641
- });
642
-
643
- const call = new FunctionCall(
644
- artifact.name,
713
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
714
+ await this.stateMachine.contractSyncService.ensureContractSynced(
645
715
  targetContractAddress,
646
716
  functionSelector,
647
- FunctionType.UTILITY,
648
- false,
649
- false,
650
- args,
651
- [],
717
+ async (call, execScopes) => {
718
+ await this.executeUtilityCall(call, execScopes, jobId);
719
+ },
720
+ blockHeader,
721
+ jobId,
722
+ await this.keyStore.getAccounts(),
652
723
  );
653
724
 
654
- return this.executeUtilityCall(call);
725
+ const call = FunctionCall.from({
726
+ name: artifact.name,
727
+ to: targetContractAddress,
728
+ selector: functionSelector,
729
+ type: FunctionType.UTILITY,
730
+ hideMsgSender: false,
731
+ isStatic: false,
732
+ args,
733
+ returnTypes: [],
734
+ });
735
+
736
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId);
655
737
  }
656
738
 
657
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
739
+ private async executeUtilityCall(call: FunctionCall, scopes: AztecAddress[], jobId: string): Promise<Fr[]> {
658
740
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
659
741
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
660
742
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -667,23 +749,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
667
749
 
668
750
  try {
669
751
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
670
- const oracle = new UtilityExecutionOracle(
671
- call.to,
672
- [],
673
- [],
752
+ const oracle = new UtilityExecutionOracle({
753
+ contractAddress: call.to,
754
+ authWitnesses: [],
755
+ capsules: [],
674
756
  anchorBlockHeader,
675
- this.contractStore,
676
- this.noteStore,
677
- this.keyStore,
678
- this.addressStore,
679
- this.stateMachine.node,
680
- this.stateMachine.anchorBlockStore,
681
- this.recipientTaggingStore,
682
- this.senderAddressBookStore,
683
- this.capsuleStore,
684
- this.privateEventStore,
685
- TXE_JOB_ID,
686
- );
757
+ contractStore: this.contractStore,
758
+ noteStore: this.noteStore,
759
+ keyStore: this.keyStore,
760
+ addressStore: this.addressStore,
761
+ aztecNode: this.stateMachine.node,
762
+ recipientTaggingStore: this.recipientTaggingStore,
763
+ senderAddressBookStore: this.senderAddressBookStore,
764
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
765
+ privateEventStore: this.privateEventStore,
766
+ messageContextService: this.stateMachine.messageContextService,
767
+ contractSyncService: this.contractSyncService,
768
+ l2TipsStore: this.stateMachine.node,
769
+ jobId,
770
+ scopes,
771
+ });
687
772
  const acirExecutionResult = await new WASMSimulator()
688
773
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
689
774
  .catch((err: Error) => {
@@ -699,10 +784,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
699
784
  );
700
785
  });
701
786
 
702
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
787
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
703
788
  return witnessMapToFields(acirExecutionResult.returnWitness);
704
789
  } catch (err) {
705
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
790
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
706
791
  }
707
792
  }
708
793