@aztec/txe 0.0.1-commit.6d3c34e → 0.0.1-commit.7035c9bd6

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 (65) 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 +23 -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 +144 -62
  15. package/dest/rpc_translator.d.ts +92 -81
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +323 -176
  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 +34 -178
  21. package/dest/state_machine/dummy_p2p_client.d.ts +16 -12
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +28 -16
  24. package/dest/state_machine/index.d.ts +7 -5
  25. package/dest/state_machine/index.d.ts.map +1 -1
  26. package/dest/state_machine/index.js +39 -12
  27. package/dest/state_machine/mock_epoch_cache.d.ts +24 -8
  28. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  29. package/dest/state_machine/mock_epoch_cache.js +43 -9
  30. package/dest/state_machine/synchronizer.d.ts +6 -6
  31. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  32. package/dest/state_machine/synchronizer.js +3 -3
  33. package/dest/txe_session.d.ts +12 -6
  34. package/dest/txe_session.d.ts.map +1 -1
  35. package/dest/txe_session.js +112 -28
  36. package/dest/util/encoding.d.ts +17 -17
  37. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  38. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  39. package/dest/util/txe_public_contract_data_source.js +5 -22
  40. package/dest/utils/block_creation.d.ts +4 -4
  41. package/dest/utils/block_creation.d.ts.map +1 -1
  42. package/dest/utils/block_creation.js +18 -4
  43. package/dest/utils/tx_effect_creation.d.ts +2 -3
  44. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  45. package/dest/utils/tx_effect_creation.js +3 -6
  46. package/package.json +16 -16
  47. package/src/constants.ts +0 -1
  48. package/src/index.ts +89 -52
  49. package/src/oracle/interfaces.ts +32 -31
  50. package/src/oracle/txe_oracle_public_context.ts +16 -18
  51. package/src/oracle/txe_oracle_top_level_context.ts +178 -111
  52. package/src/rpc_translator.ts +360 -202
  53. package/src/state_machine/archiver.ts +37 -234
  54. package/src/state_machine/dummy_p2p_client.ts +40 -22
  55. package/src/state_machine/index.ts +53 -11
  56. package/src/state_machine/mock_epoch_cache.ts +53 -14
  57. package/src/state_machine/synchronizer.ts +5 -5
  58. package/src/txe_session.ts +129 -88
  59. package/src/util/txe_public_contract_data_source.ts +10 -36
  60. package/src/utils/block_creation.ts +19 -16
  61. package/src/utils/tx_effect_creation.ts +3 -11
  62. package/dest/util/txe_contract_store.d.ts +0 -12
  63. package/dest/util/txe_contract_store.d.ts.map +0 -1
  64. package/dest/util/txe_contract_store.js +0 -22
  65. package/src/util/txe_contract_store.ts +0 -36
@@ -21,7 +21,7 @@ import { makeGlobalVariables } from '@aztec/stdlib/testing';
21
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
22
22
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
23
23
  import { ForkCheckpoint } from '@aztec/world-state';
24
- import { DEFAULT_ADDRESS, TXE_JOB_ID } from '../constants.js';
24
+ import { DEFAULT_ADDRESS } from '../constants.js';
25
25
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
26
26
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
27
27
  export class TXEOracleTopLevelContext {
@@ -40,10 +40,11 @@ export class TXEOracleTopLevelContext {
40
40
  version;
41
41
  chainId;
42
42
  authwits;
43
+ contractSyncService;
43
44
  isMisc;
44
45
  isTxe;
45
46
  logger;
46
- constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits){
47
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits, contractSyncService){
47
48
  this.stateMachine = stateMachine;
48
49
  this.contractStore = contractStore;
49
50
  this.noteStore = noteStore;
@@ -59,45 +60,48 @@ export class TXEOracleTopLevelContext {
59
60
  this.version = version;
60
61
  this.chainId = chainId;
61
62
  this.authwits = authwits;
63
+ this.contractSyncService = contractSyncService;
62
64
  this.isMisc = true;
63
65
  this.isTxe = true;
64
66
  this.logger = createLogger('txe:top_level_context');
65
67
  this.logger.debug('Entering Top Level Context');
66
68
  }
67
- utilityAssertCompatibleOracleVersion(version) {
69
+ assertCompatibleOracleVersion(version) {
68
70
  if (version !== ORACLE_VERSION) {
69
71
  throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
70
72
  }
71
73
  }
72
74
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
73
75
  // setup.
74
- utilityGetRandomField() {
76
+ getRandomField() {
75
77
  return Fr.random();
76
78
  }
77
79
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
78
- utilityDebugLog(level, message, fields) {
80
+ log(level, message, fields) {
79
81
  if (!LogLevels[level]) {
80
- throw new Error(`Invalid debug log level: ${level}`);
82
+ throw new Error(`Invalid log level: ${level}`);
81
83
  }
82
84
  const levelName = LogLevels[level];
83
85
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
84
86
  module: `${this.logger.module}:debug_log`
85
87
  });
88
+ return Promise.resolve();
86
89
  }
87
- txeGetDefaultAddress() {
90
+ getDefaultAddress() {
88
91
  return DEFAULT_ADDRESS;
89
92
  }
90
- async txeGetNextBlockNumber() {
93
+ async getNextBlockNumber() {
91
94
  return BlockNumber(await this.getLastBlockNumber() + 1);
92
95
  }
93
- txeGetNextBlockTimestamp() {
96
+ getNextBlockTimestamp() {
94
97
  return Promise.resolve(this.nextBlockTimestamp);
95
98
  }
96
- async txeGetLastBlockTimestamp() {
99
+ async getLastBlockTimestamp() {
97
100
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
98
101
  }
99
- async txeGetLastTxEffects() {
100
- const block = await this.stateMachine.archiver.getL2Block('latest');
102
+ async getLastTxEffects() {
103
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
104
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
101
105
  if (block.body.txEffects.length != 1) {
102
106
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
103
107
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
@@ -109,7 +113,19 @@ export class TXEOracleTopLevelContext {
109
113
  nullifiers: txEffects.nullifiers
110
114
  };
111
115
  }
112
- async txeGetPrivateEvents(selector, contractAddress, scope) {
116
+ async syncContractNonOracleMethod(contractAddress, scope, jobId) {
117
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
118
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
119
+ return;
120
+ }
121
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
122
+ await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
123
+ await this.executeUtilityCall(call, execScopes, jobId);
124
+ }, blockHeader, jobId, [
125
+ scope
126
+ ]);
127
+ }
128
+ async getPrivateEvents(selector, contractAddress, scope) {
113
129
  return (await this.privateEventStore.getPrivateEvents(selector, {
114
130
  contractAddress,
115
131
  scopes: [
@@ -119,17 +135,17 @@ export class TXEOracleTopLevelContext {
119
135
  toBlock: await this.getLastBlockNumber() + 1
120
136
  })).map((e)=>e.packedEvent);
121
137
  }
122
- async txeAdvanceBlocksBy(blocks) {
138
+ async advanceBlocksBy(blocks) {
123
139
  this.logger.debug(`time traveling ${blocks} blocks`);
124
140
  for(let i = 0; i < blocks; i++){
125
141
  await this.mineBlock();
126
142
  }
127
143
  }
128
- txeAdvanceTimestampBy(duration) {
144
+ advanceTimestampBy(duration) {
129
145
  this.logger.debug(`time traveling ${duration} seconds`);
130
146
  this.nextBlockTimestamp += duration;
131
147
  }
132
- async txeDeploy(artifact, instance, secret) {
148
+ async deploy(artifact, instance, secret) {
133
149
  // Emit deployment nullifier
134
150
  await this.mineBlock({
135
151
  nullifiers: [
@@ -137,25 +153,25 @@ export class TXEOracleTopLevelContext {
137
153
  ]
138
154
  });
139
155
  if (!secret.equals(Fr.ZERO)) {
140
- await this.txeAddAccount(artifact, instance, secret);
156
+ await this.addAccount(artifact, instance, secret);
141
157
  } else {
142
158
  await this.contractStore.addContractInstance(instance);
143
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
159
+ await this.contractStore.addContractArtifact(artifact);
144
160
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
145
161
  }
146
162
  }
147
- async txeAddAccount(artifact, instance, secret) {
163
+ async addAccount(artifact, instance, secret) {
148
164
  const partialAddress = await computePartialAddress(instance);
149
165
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
150
166
  await this.contractStore.addContractInstance(instance);
151
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
167
+ await this.contractStore.addContractArtifact(artifact);
152
168
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
153
169
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
154
170
  await this.addressStore.addCompleteAddress(completeAddress);
155
171
  this.logger.debug(`Created account ${completeAddress.address}`);
156
172
  return completeAddress;
157
173
  }
158
- async txeCreateAccount(secret) {
174
+ async createAccount(secret) {
159
175
  // This is a foot gun !
160
176
  const completeAddress = await this.keyStore.addAccount(secret, secret);
161
177
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -163,7 +179,7 @@ export class TXEOracleTopLevelContext {
163
179
  this.logger.debug(`Created account ${completeAddress.address}`);
164
180
  return completeAddress;
165
181
  }
166
- async txeAddAuthWitness(address, messageHash) {
182
+ async addAuthWitness(address, messageHash) {
167
183
  const account = await this.accountStore.getAccount(address);
168
184
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
169
185
  const schnorr = new Schnorr();
@@ -174,7 +190,7 @@ export class TXEOracleTopLevelContext {
174
190
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
175
191
  }
176
192
  async mineBlock(options = {}) {
177
- const blockNumber = await this.txeGetNextBlockNumber();
193
+ const blockNumber = await this.getNextBlockNumber();
178
194
  const txEffect = TxEffect.empty();
179
195
  txEffect.nullifiers = [
180
196
  getSingleTxBlockRequestHash(blockNumber),
@@ -196,35 +212,73 @@ export class TXEOracleTopLevelContext {
196
212
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
197
213
  await this.stateMachine.handleL2Block(block);
198
214
  }
199
- async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
215
+ async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
200
216
  this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
201
217
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
202
218
  if (!artifact) {
203
219
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
204
220
  throw new Error(message);
205
221
  }
222
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
223
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
224
+ const effectiveScopes = from.isZero() ? [] : [
225
+ from
226
+ ];
206
227
  // Sync notes before executing private function to discover notes from previous transactions
207
- const utilityExecutor = async (call)=>{
208
- await this.executeUtilityCall(call);
228
+ const utilityExecutor = async (call, execScopes)=>{
229
+ await this.executeUtilityCall(call, execScopes, jobId);
209
230
  };
210
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
211
- const blockNumber = await this.txeGetNextBlockNumber();
231
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
232
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
233
+ const blockNumber = await this.getNextBlockNumber();
212
234
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
213
235
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
214
236
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
215
237
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
216
238
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
217
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
218
239
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
219
240
  const noteCache = new ExecutionNoteCache(protocolNullifier);
241
+ // In production, the account contract sets the min revertible counter before calling the app function.
242
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
243
+ // marking all side effects as revertible.
244
+ const minRevertibleSideEffectCounter = 1;
245
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
220
246
  const taggingIndexCache = new ExecutionTaggingIndexCache();
221
247
  const simulator = new WASMSimulator();
222
- const privateExecutionOracle = 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, utilityExecutor, /** 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([
223
- new HashedValues(args, argsHash)
224
- ]), noteCache, taggingIndexCache, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.stateMachine.anchorBlockStore, this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, TXE_JOB_ID, 0, 1, undefined, undefined, /**
225
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
226
- * contract would perform, including setting senderForTags.
227
- */ from, simulator);
248
+ const privateExecutionOracle = new PrivateExecutionOracle({
249
+ argsHash,
250
+ txContext,
251
+ callContext,
252
+ anchorBlockHeader: blockHeader,
253
+ utilityExecutor,
254
+ authWitnesses: Array.from(this.authwits.values()),
255
+ capsules: [],
256
+ executionCache: HashedValuesCache.create([
257
+ new HashedValues(args, argsHash)
258
+ ]),
259
+ noteCache,
260
+ taggingIndexCache,
261
+ contractStore: this.contractStore,
262
+ noteStore: this.noteStore,
263
+ keyStore: this.keyStore,
264
+ addressStore: this.addressStore,
265
+ aztecNode: this.stateMachine.node,
266
+ senderTaggingStore: this.senderTaggingStore,
267
+ recipientTaggingStore: this.recipientTaggingStore,
268
+ senderAddressBookStore: this.senderAddressBookStore,
269
+ capsuleStore: this.capsuleStore,
270
+ privateEventStore: this.privateEventStore,
271
+ contractSyncService: this.stateMachine.contractSyncService,
272
+ jobId,
273
+ totalPublicCalldataCount: 0,
274
+ sideEffectCounter: minRevertibleSideEffectCounter,
275
+ scopes: effectiveScopes,
276
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
277
+ // contract would perform, including setting senderForTags.
278
+ senderForTags: from,
279
+ simulator,
280
+ messageContextService: this.stateMachine.messageContextService
281
+ });
228
282
  // 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.
229
283
  let result;
230
284
  let executionResult;
@@ -236,21 +290,19 @@ export class TXEOracleTopLevelContext {
236
290
  r.publicInputs.publicTeardownCallRequest
237
291
  ]));
238
292
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
239
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
293
+ const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
240
294
  return new HashedValues(calldata, r.calldataHash);
241
295
  }));
242
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
243
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
244
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
245
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
296
+ noteCache.finish();
297
+ const nonceGenerator = noteCache.getNonceGenerator();
298
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
246
299
  } catch (err) {
247
300
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
248
301
  }
249
- // According to the protocol rules, the nonce generator for the note hashes
250
- // can either be the first nullifier in the tx or the hash of the initial tx request
251
- // if there are none.
252
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
253
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractStore);
302
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
303
+ // the nonce generator for the note hashes.
304
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
305
+ const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
254
306
  const globals = makeGlobalVariables();
255
307
  globals.blockNumber = blockNumber;
256
308
  globals.timestamp = this.nextBlockTimestamp;
@@ -258,7 +310,8 @@ export class TXEOracleTopLevelContext {
258
310
  globals.version = this.version;
259
311
  globals.gasFees = GasFees.empty();
260
312
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
261
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
313
+ const bindings = this.logger.getBindings();
314
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
262
315
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
263
316
  const config = PublicSimulatorConfig.from({
264
317
  skipFeeEnforcement: true,
@@ -267,7 +320,7 @@ export class TXEOracleTopLevelContext {
267
320
  collectStatistics: false,
268
321
  collectCallMetadata: true
269
322
  });
270
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config), new TestDateProvider());
323
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
271
324
  const tx = await Tx.create({
272
325
  data: publicInputs,
273
326
  chonkProof: ChonkProof.empty(),
@@ -317,9 +370,9 @@ export class TXEOracleTopLevelContext {
317
370
  await forkedWorldTrees.close();
318
371
  return executionResult.returnValues ?? [];
319
372
  }
320
- async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
373
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
321
374
  this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
322
- const blockNumber = await this.txeGetNextBlockNumber();
375
+ const blockNumber = await this.getNextBlockNumber();
323
376
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
324
377
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
325
378
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
@@ -334,7 +387,8 @@ export class TXEOracleTopLevelContext {
334
387
  globals.version = this.version;
335
388
  globals.gasFees = GasFees.empty();
336
389
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
337
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
390
+ const bindings2 = this.logger.getBindings();
391
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
338
392
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
339
393
  const config = PublicSimulatorConfig.from({
340
394
  skipFeeEnforcement: true,
@@ -343,8 +397,8 @@ export class TXEOracleTopLevelContext {
343
397
  collectStatistics: false,
344
398
  collectCallMetadata: true
345
399
  });
346
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
347
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
400
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
401
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
348
402
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
349
403
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
350
404
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
@@ -357,7 +411,7 @@ export class TXEOracleTopLevelContext {
357
411
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
358
412
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
359
413
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
360
- const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
414
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
361
415
  const tx = await Tx.create({
362
416
  data: txData,
363
417
  chonkProof: ChonkProof.empty(),
@@ -410,19 +464,29 @@ export class TXEOracleTopLevelContext {
410
464
  await forkedWorldTrees.close();
411
465
  return returnValues ?? [];
412
466
  }
413
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
467
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
414
468
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
415
469
  if (!artifact) {
416
470
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
417
471
  }
418
472
  // Sync notes before executing utility function to discover notes from previous transactions
419
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async (call)=>{
420
- await this.executeUtilityCall(call);
473
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
475
+ await this.executeUtilityCall(call, execScopes, jobId);
476
+ }, blockHeader, jobId, 'ALL_SCOPES');
477
+ const call = FunctionCall.from({
478
+ name: artifact.name,
479
+ to: targetContractAddress,
480
+ selector: functionSelector,
481
+ type: FunctionType.UTILITY,
482
+ hideMsgSender: false,
483
+ isStatic: false,
484
+ args,
485
+ returnTypes: []
421
486
  });
422
- const call = new FunctionCall(artifact.name, targetContractAddress, functionSelector, FunctionType.UTILITY, false, false, args, []);
423
- return this.executeUtilityCall(call);
487
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
424
488
  }
425
- async executeUtilityCall(call) {
489
+ async executeUtilityCall(call, scopes, jobId) {
426
490
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
427
491
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
428
492
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -433,7 +497,25 @@ export class TXEOracleTopLevelContext {
433
497
  });
434
498
  try {
435
499
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
436
- const oracle = new UtilityExecutionOracle(call.to, [], [], anchorBlockHeader, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.stateMachine.anchorBlockStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, TXE_JOB_ID);
500
+ const oracle = new UtilityExecutionOracle({
501
+ contractAddress: call.to,
502
+ authWitnesses: [],
503
+ capsules: [],
504
+ anchorBlockHeader,
505
+ contractStore: this.contractStore,
506
+ noteStore: this.noteStore,
507
+ keyStore: this.keyStore,
508
+ addressStore: this.addressStore,
509
+ aztecNode: this.stateMachine.node,
510
+ recipientTaggingStore: this.recipientTaggingStore,
511
+ senderAddressBookStore: this.senderAddressBookStore,
512
+ capsuleStore: this.capsuleStore,
513
+ privateEventStore: this.privateEventStore,
514
+ messageContextService: this.stateMachine.messageContextService,
515
+ contractSyncService: this.contractSyncService,
516
+ jobId,
517
+ scopes
518
+ });
437
519
  const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
438
520
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
439
521
  throw new ExecutionError(err.message, {
@@ -443,10 +525,10 @@ export class TXEOracleTopLevelContext {
443
525
  cause: err
444
526
  });
445
527
  });
446
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
528
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
447
529
  return witnessMapToFields(acirExecutionResult.returnWitness);
448
530
  } catch (err) {
449
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
531
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
450
532
  }
451
533
  }
452
534
  close() {