@aztec/txe 0.0.1-commit.1bea0213 → 0.0.1-commit.217f559981

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 (52) hide show
  1. package/dest/index.d.ts +1 -1
  2. package/dest/index.d.ts.map +1 -1
  3. package/dest/index.js +82 -50
  4. package/dest/oracle/interfaces.d.ts +3 -3
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +3 -4
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +5 -6
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +92 -31
  12. package/dest/rpc_translator.d.ts +9 -9
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +42 -31
  15. package/dest/state_machine/archiver.d.ts +1 -1
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +2 -0
  18. package/dest/state_machine/dummy_p2p_client.d.ts +15 -11
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +27 -15
  21. package/dest/state_machine/index.d.ts +5 -5
  22. package/dest/state_machine/index.d.ts.map +1 -1
  23. package/dest/state_machine/index.js +15 -10
  24. package/dest/state_machine/mock_epoch_cache.d.ts +3 -1
  25. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  26. package/dest/state_machine/mock_epoch_cache.js +4 -0
  27. package/dest/txe_session.d.ts +4 -6
  28. package/dest/txe_session.d.ts.map +1 -1
  29. package/dest/txe_session.js +69 -17
  30. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  31. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  32. package/dest/util/txe_public_contract_data_source.js +5 -22
  33. package/dest/utils/block_creation.d.ts +1 -1
  34. package/dest/utils/block_creation.d.ts.map +1 -1
  35. package/dest/utils/block_creation.js +3 -1
  36. package/package.json +15 -15
  37. package/src/index.ts +83 -49
  38. package/src/oracle/interfaces.ts +2 -2
  39. package/src/oracle/txe_oracle_public_context.ts +3 -5
  40. package/src/oracle/txe_oracle_top_level_context.ts +113 -85
  41. package/src/rpc_translator.ts +44 -26
  42. package/src/state_machine/archiver.ts +2 -0
  43. package/src/state_machine/dummy_p2p_client.ts +39 -21
  44. package/src/state_machine/index.ts +25 -9
  45. package/src/state_machine/mock_epoch_cache.ts +5 -0
  46. package/src/txe_session.ts +73 -77
  47. package/src/util/txe_public_contract_data_source.ts +10 -36
  48. package/src/utils/block_creation.ts +3 -1
  49. package/dest/util/txe_contract_store.d.ts +0 -12
  50. package/dest/util/txe_contract_store.d.ts.map +0 -1
  51. package/dest/util/txe_contract_store.js +0 -22
  52. package/src/util/txe_contract_store.ts +0 -36
package/src/index.ts CHANGED
@@ -9,9 +9,12 @@ import { Fr } from '@aztec/aztec.js/fields';
9
9
  import { PublicKeys, deriveKeys } from '@aztec/aztec.js/keys';
10
10
  import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
11
11
  import type { Logger } from '@aztec/foundation/log';
12
- import { type ProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
12
+ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
13
+ import { protocolContractNames } from '@aztec/protocol-contracts';
13
14
  import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
15
+ import { ContractStore } from '@aztec/pxe/server';
14
16
  import { computeArtifactHash } from '@aztec/stdlib/contract';
17
+ import type { ContractArtifactWithHash } from '@aztec/stdlib/contract';
15
18
  import type { ApiSchemaFor } from '@aztec/stdlib/schemas';
16
19
  import { zodFor } from '@aztec/stdlib/schemas';
17
20
 
@@ -33,18 +36,24 @@ import {
33
36
  fromSingle,
34
37
  toSingle,
35
38
  } from './util/encoding.js';
36
- import type { ContractArtifactWithHash } from './util/txe_contract_store.js';
37
39
 
38
40
  const sessions = new Map<number, TXESession>();
39
41
 
40
42
  /*
41
43
  * TXE typically has to load the same contract artifacts over and over again for multiple tests,
42
- * so we cache them here to avoid both loading them from disk repeatedly and computing their artifact hashes
44
+ * so we cache them here to avoid loading from disk repeatedly.
45
+ *
46
+ * The in-flight map coalesces concurrent requests for the same cache key so that
47
+ * computeArtifactHash (very expensive) is only run once even under parallelism.
43
48
  */
44
49
  const TXEArtifactsCache = new Map<
45
50
  string,
46
51
  { artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }
47
52
  >();
53
+ const TXEArtifactsCacheInFlight = new Map<
54
+ string,
55
+ Promise<{ artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }>
56
+ >();
48
57
 
49
58
  type TXEForeignCallInput = {
50
59
  session_id: number;
@@ -68,7 +77,7 @@ const TXEForeignCallInputSchema = zodFor<TXEForeignCallInput>()(
68
77
  );
69
78
 
70
79
  class TXEDispatcher {
71
- private protocolContracts!: ProtocolContract[];
80
+ private contractStore!: ContractStore;
72
81
 
73
82
  constructor(private logger: Logger) {}
74
83
 
@@ -135,29 +144,36 @@ class TXEDispatcher {
135
144
  this.logger.debug(`Using cached artifact for ${cacheKey}`);
136
145
  ({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
137
146
  } else {
138
- this.logger.debug(`Loading compiled artifact ${artifactPath}`);
139
- const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8')) as NoirCompiledContract;
140
- const artifactWithoutHash = loadContractArtifact(artifactJSON);
141
- artifact = {
142
- ...artifactWithoutHash,
143
- // Artifact hash is *very* expensive to compute, so we do it here once
144
- // and the TXE contract data provider can cache it
145
- artifactHash: await computeArtifactHash(artifactWithoutHash),
146
- };
147
- this.logger.debug(
148
- `Deploy ${
149
- artifact.name
150
- } with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
151
- );
152
- instance = await getContractInstanceFromInstantiationParams(artifact, {
153
- constructorArgs: decodedArgs,
154
- skipArgsDecoding: true,
155
- salt: Fr.ONE,
156
- publicKeys,
157
- constructorArtifact: initializer ? initializer : undefined,
158
- deployer: AztecAddress.ZERO,
159
- });
160
- TXEArtifactsCache.set(cacheKey, { artifact, instance });
147
+ if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
148
+ this.logger.debug(`Loading compiled artifact ${artifactPath}`);
149
+ const compute = async () => {
150
+ const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8')) as NoirCompiledContract;
151
+ const artifactWithoutHash = loadContractArtifact(artifactJSON);
152
+ const computedArtifact: ContractArtifactWithHash = {
153
+ ...artifactWithoutHash,
154
+ // Artifact hash is *very* expensive to compute, so we do it here once
155
+ // and the TXE contract data provider can cache it
156
+ artifactHash: await computeArtifactHash(artifactWithoutHash),
157
+ };
158
+ this.logger.debug(
159
+ `Deploy ${computedArtifact.name} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
160
+ );
161
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
162
+ constructorArgs: decodedArgs,
163
+ skipArgsDecoding: true,
164
+ salt: Fr.ONE,
165
+ publicKeys,
166
+ constructorArtifact: initializer ? initializer : undefined,
167
+ deployer: AztecAddress.ZERO,
168
+ });
169
+ const result = { artifact: computedArtifact, instance: computedInstance };
170
+ TXEArtifactsCache.set(cacheKey, result);
171
+ TXEArtifactsCacheInFlight.delete(cacheKey);
172
+ return result;
173
+ };
174
+ TXEArtifactsCacheInFlight.set(cacheKey, compute());
175
+ }
176
+ ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
161
177
  }
162
178
 
163
179
  inputs.splice(0, 1, artifact, instance, toSingle(secret));
@@ -175,23 +191,35 @@ class TXEDispatcher {
175
191
  this.logger.debug(`Using cached artifact for ${cacheKey}`);
176
192
  ({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
177
193
  } else {
178
- const keys = await deriveKeys(secret);
179
- const args = [keys.publicKeys.masterIncomingViewingPublicKey.x, keys.publicKeys.masterIncomingViewingPublicKey.y];
180
- artifact = {
181
- ...SchnorrAccountContractArtifact,
182
- // Artifact hash is *very* expensive to compute, so we do it here once
183
- // and the TXE contract data provider can cache it
184
- artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact),
185
- };
186
- instance = await getContractInstanceFromInstantiationParams(artifact, {
187
- constructorArgs: args,
188
- skipArgsDecoding: true,
189
- salt: Fr.ONE,
190
- publicKeys: keys.publicKeys,
191
- constructorArtifact: 'constructor',
192
- deployer: AztecAddress.ZERO,
193
- });
194
- TXEArtifactsCache.set(cacheKey, { artifact, instance });
194
+ if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
195
+ const compute = async () => {
196
+ const keys = await deriveKeys(secret);
197
+ const args = [
198
+ keys.publicKeys.masterIncomingViewingPublicKey.x,
199
+ keys.publicKeys.masterIncomingViewingPublicKey.y,
200
+ ];
201
+ const computedArtifact: ContractArtifactWithHash = {
202
+ ...SchnorrAccountContractArtifact,
203
+ // Artifact hash is *very* expensive to compute, so we do it here once
204
+ // and the TXE contract data provider can cache it
205
+ artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact),
206
+ };
207
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
208
+ constructorArgs: args,
209
+ skipArgsDecoding: true,
210
+ salt: Fr.ONE,
211
+ publicKeys: keys.publicKeys,
212
+ constructorArtifact: 'constructor',
213
+ deployer: AztecAddress.ZERO,
214
+ });
215
+ const result = { artifact: computedArtifact, instance: computedInstance };
216
+ TXEArtifactsCache.set(cacheKey, result);
217
+ TXEArtifactsCacheInFlight.delete(cacheKey);
218
+ return result;
219
+ };
220
+ TXEArtifactsCacheInFlight.set(cacheKey, compute());
221
+ }
222
+ ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
195
223
  }
196
224
 
197
225
  inputs.splice(0, 0, artifact, instance);
@@ -204,12 +232,18 @@ class TXEDispatcher {
204
232
 
205
233
  if (!sessions.has(sessionId)) {
206
234
  this.logger.debug(`Creating new session ${sessionId}`);
207
- if (!this.protocolContracts) {
208
- this.protocolContracts = await Promise.all(
209
- protocolContractNames.map(name => new BundledProtocolContractsProvider().getProtocolContractArtifact(name)),
210
- );
235
+ if (!this.contractStore) {
236
+ const kvStore = await openTmpStore('txe-contracts');
237
+ this.contractStore = new ContractStore(kvStore);
238
+ const provider = new BundledProtocolContractsProvider();
239
+ for (const name of protocolContractNames) {
240
+ const { instance, artifact } = await provider.getProtocolContractArtifact(name);
241
+ await this.contractStore.addContractArtifact(artifact);
242
+ await this.contractStore.addContractInstance(instance);
243
+ }
244
+ this.logger.debug('Registered protocol contracts in shared contract store');
211
245
  }
212
- sessions.set(sessionId, await TXESession.init(this.protocolContracts));
246
+ sessions.set(sessionId, await TXESession.init(this.contractStore));
213
247
  }
214
248
 
215
249
  switch (functionName) {
@@ -33,7 +33,7 @@ export interface IAvmExecutionOracle {
33
33
  avmOpcodeVersion(): Promise<Fr>;
34
34
  avmOpcodeEmitNullifier(nullifier: Fr): Promise<void>;
35
35
  avmOpcodeEmitNoteHash(noteHash: Fr): Promise<void>;
36
- avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean>;
36
+ avmOpcodeNullifierExists(siloedNullifier: Fr): Promise<boolean>;
37
37
  avmOpcodeStorageWrite(slot: Fr, value: Fr): Promise<void>;
38
38
  avmOpcodeStorageRead(slot: Fr, contractAddress: AztecAddress): Promise<Fr>;
39
39
  }
@@ -72,7 +72,7 @@ export interface ITxeExecutionOracle {
72
72
  argsHash: Fr,
73
73
  isStaticCall: boolean,
74
74
  ): Promise<Fr[]>;
75
- txeSimulateUtilityFunction(
75
+ txeExecuteUtilityFunction(
76
76
  targetContractAddress: AztecAddress,
77
77
  functionSelector: FunctionSelector,
78
78
  args: Fr[],
@@ -78,13 +78,11 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
78
78
  this.transientUniqueNoteHashes.push(siloedNoteHash);
79
79
  }
80
80
 
81
- async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
82
- const nullifier = await siloNullifier(targetAddress, innerNullifier!);
83
-
81
+ async avmOpcodeNullifierExists(siloedNullifier: Fr): Promise<boolean> {
84
82
  const treeIndex = (
85
- await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()])
83
+ await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()])
86
84
  )[0];
87
- const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(nullifier));
85
+ const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(siloedNullifier));
88
86
 
89
87
  return treeIndex !== undefined || transientIndex !== undefined;
90
88
  }
@@ -12,9 +12,11 @@ import { Fr } from '@aztec/foundation/curves/bn254';
12
12
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
13
13
  import { TestDateProvider } from '@aztec/foundation/timer';
14
14
  import type { KeyStore } from '@aztec/key-store';
15
+ import type { AccessScopes } from '@aztec/pxe/client/lazy';
15
16
  import {
16
17
  AddressStore,
17
18
  CapsuleStore,
19
+ type ContractStore,
18
20
  NoteStore,
19
21
  ORACLE_VERSION,
20
22
  PrivateEventStore,
@@ -22,7 +24,6 @@ import {
22
24
  SenderAddressBookStore,
23
25
  SenderTaggingStore,
24
26
  enrichPublicSimulationError,
25
- syncState,
26
27
  } from '@aztec/pxe/server';
27
28
  import {
28
29
  ExecutionNoteCache,
@@ -84,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
84
85
  import { DEFAULT_ADDRESS } from '../constants.js';
85
86
  import type { TXEStateMachine } from '../state_machine/index.js';
86
87
  import type { TXEAccountStore } from '../util/txe_account_store.js';
87
- import type { TXEContractStore } from '../util/txe_contract_store.js';
88
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
89
89
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
90
90
  import type { ITxeExecutionOracle } from './interfaces.js';
@@ -97,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
97
97
 
98
98
  constructor(
99
99
  private stateMachine: TXEStateMachine,
100
- private contractStore: TXEContractStore,
100
+ private contractStore: ContractStore,
101
101
  private noteStore: NoteStore,
102
102
  private keyStore: KeyStore,
103
103
  private addressStore: AddressStore,
@@ -132,13 +132,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
132
132
  }
133
133
 
134
134
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
135
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
135
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
136
136
  if (!LogLevels[level]) {
137
- throw new Error(`Invalid debug log level: ${level}`);
137
+ throw new Error(`Invalid log level: ${level}`);
138
138
  }
139
139
  const levelName = LogLevels[level];
140
140
 
141
141
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
142
+ return Promise.resolve();
142
143
  }
143
144
 
144
145
  txeGetDefaultAddress(): AztecAddress {
@@ -210,7 +211,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
210
211
  await this.txeAddAccount(artifact, instance, secret);
211
212
  } else {
212
213
  await this.contractStore.addContractInstance(instance);
213
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
214
+ await this.contractStore.addContractArtifact(artifact);
214
215
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
215
216
  }
216
217
  }
@@ -220,7 +221,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
220
221
 
221
222
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
222
223
  await this.contractStore.addContractInstance(instance);
223
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
224
+ await this.contractStore.addContractArtifact(artifact);
224
225
 
225
226
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
226
227
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -297,12 +298,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
297
298
  throw new Error(message);
298
299
  }
299
300
 
301
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
302
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
303
+ const effectiveScopes = from.isZero() ? [] : [from];
304
+
300
305
  // Sync notes before executing private function to discover notes from previous transactions
301
- const utilityExecutor = async (call: FunctionCall) => {
302
- await this.executeUtilityCall(call);
306
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
307
+ await this.executeUtilityCall(call, execScopes);
303
308
  };
304
309
 
305
- await syncState(targetContractAddress, this.contractStore, functionSelector, utilityExecutor);
310
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
311
+ await this.stateMachine.contractSyncService.ensureContractSynced(
312
+ targetContractAddress,
313
+ functionSelector,
314
+ utilityExecutor,
315
+ blockHeader,
316
+ this.jobId,
317
+ effectiveScopes,
318
+ );
306
319
 
307
320
  const blockNumber = await this.txeGetNextBlockNumber();
308
321
 
@@ -314,8 +327,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
314
327
 
315
328
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
316
329
 
317
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
318
-
319
330
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
320
331
  const noteCache = new ExecutionNoteCache(protocolNullifier);
321
332
  // In production, the account contract sets the min revertible counter before calling the app function.
@@ -327,43 +338,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
327
338
 
328
339
  const simulator = new WASMSimulator();
329
340
 
330
- const privateExecutionOracle = new PrivateExecutionOracle(
341
+ const privateExecutionOracle = new PrivateExecutionOracle({
331
342
  argsHash,
332
343
  txContext,
333
344
  callContext,
334
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
335
- blockHeader,
345
+ anchorBlockHeader: blockHeader,
336
346
  utilityExecutor,
337
- /** List of transient auth witnesses to be used during this simulation */
338
- Array.from(this.authwits.values()),
339
- /** List of transient auth witnesses to be used during this simulation */
340
- [],
341
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
347
+ authWitnesses: Array.from(this.authwits.values()),
348
+ capsules: [],
349
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
342
350
  noteCache,
343
351
  taggingIndexCache,
344
- this.contractStore,
345
- this.noteStore,
346
- this.keyStore,
347
- this.addressStore,
348
- this.stateMachine.node,
349
- this.stateMachine.anchorBlockStore,
350
- this.senderTaggingStore,
351
- this.recipientTaggingStore,
352
- this.senderAddressBookStore,
353
- this.capsuleStore,
354
- this.privateEventStore,
355
- this.jobId,
356
- 0, // totalPublicArgsCount
357
- minRevertibleSideEffectCounter, // (start) sideEffectCounter
358
- undefined, // log
359
- undefined, // scopes
360
- /**
361
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
362
- * contract would perform, including setting senderForTags.
363
- */
364
- from,
352
+ contractStore: this.contractStore,
353
+ noteStore: this.noteStore,
354
+ keyStore: this.keyStore,
355
+ addressStore: this.addressStore,
356
+ aztecNode: this.stateMachine.node,
357
+ senderTaggingStore: this.senderTaggingStore,
358
+ recipientTaggingStore: this.recipientTaggingStore,
359
+ senderAddressBookStore: this.senderAddressBookStore,
360
+ capsuleStore: this.capsuleStore,
361
+ privateEventStore: this.privateEventStore,
362
+ contractSyncService: this.stateMachine.contractSyncService,
363
+ jobId: this.jobId,
364
+ totalPublicCalldataCount: 0,
365
+ sideEffectCounter: minRevertibleSideEffectCounter,
366
+ scopes: effectiveScopes,
367
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
368
+ // contract would perform, including setting senderForTags.
369
+ senderForTags: from,
365
370
  simulator,
366
- );
371
+ });
367
372
 
368
373
  // 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.
369
374
  let result: PrivateExecutionResult;
@@ -402,7 +407,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
402
407
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
403
408
  const { publicInputs } = await generateSimulatedProvingResult(
404
409
  result,
405
- this.contractStore,
410
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
411
+ this.stateMachine.node,
406
412
  minRevertibleSideEffectCounter,
407
413
  );
408
414
 
@@ -415,7 +421,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
415
421
 
416
422
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
417
423
 
418
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
424
+ const bindings = this.logger.getBindings();
425
+ const contractsDB = new PublicContractsDB(
426
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
427
+ bindings,
428
+ );
419
429
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
420
430
  const config = PublicSimulatorConfig.from({
421
431
  skipFeeEnforcement: true,
@@ -428,8 +438,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
428
438
  globals,
429
439
  guardedMerkleTrees,
430
440
  contractsDB,
431
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
441
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
432
442
  new TestDateProvider(),
443
+ undefined,
444
+ createLogger('simulator:public-processor', bindings),
433
445
  );
434
446
 
435
447
  const tx = await Tx.create({
@@ -526,7 +538,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
526
538
 
527
539
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
528
540
 
529
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
541
+ const bindings2 = this.logger.getBindings();
542
+ const contractsDB = new PublicContractsDB(
543
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
544
+ bindings2,
545
+ );
530
546
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
531
547
  const config = PublicSimulatorConfig.from({
532
548
  skipFeeEnforcement: true,
@@ -535,8 +551,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
535
551
  collectStatistics: false,
536
552
  collectCallMetadata: true,
537
553
  });
538
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
539
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
554
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
555
+ const processor = new PublicProcessor(
556
+ globals,
557
+ guardedMerkleTrees,
558
+ contractsDB,
559
+ simulator,
560
+ new TestDateProvider(),
561
+ undefined,
562
+ createLogger('simulator:public-processor', bindings2),
563
+ );
540
564
 
541
565
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
542
566
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -567,7 +591,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
567
591
  constantData,
568
592
  /*gasUsed=*/ new Gas(0, 0),
569
593
  /*feePayer=*/ AztecAddress.zero(),
570
- /*includeByTimestamp=*/ 0n,
594
+ /*expirationTimestamp=*/ 0n,
571
595
  inputsForPublic,
572
596
  undefined,
573
597
  );
@@ -635,36 +659,40 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
635
659
  return returnValues ?? [];
636
660
  }
637
661
 
638
- async txeSimulateUtilityFunction(
639
- targetContractAddress: AztecAddress,
640
- functionSelector: FunctionSelector,
641
- args: Fr[],
642
- ) {
662
+ async txeExecuteUtilityFunction(targetContractAddress: AztecAddress, functionSelector: FunctionSelector, args: Fr[]) {
643
663
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
644
664
  if (!artifact) {
645
665
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
646
666
  }
647
667
 
648
668
  // Sync notes before executing utility function to discover notes from previous transactions
649
- await syncState(targetContractAddress, this.contractStore, functionSelector, async call => {
650
- await this.executeUtilityCall(call);
651
- });
652
-
653
- const call = new FunctionCall(
654
- artifact.name,
669
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
670
+ await this.stateMachine.contractSyncService.ensureContractSynced(
655
671
  targetContractAddress,
656
672
  functionSelector,
657
- FunctionType.UTILITY,
658
- false,
659
- false,
660
- args,
661
- [],
673
+ async (call, execScopes) => {
674
+ await this.executeUtilityCall(call, execScopes);
675
+ },
676
+ blockHeader,
677
+ this.jobId,
678
+ 'ALL_SCOPES',
662
679
  );
663
680
 
664
- return this.executeUtilityCall(call);
681
+ const call = FunctionCall.from({
682
+ name: artifact.name,
683
+ to: targetContractAddress,
684
+ selector: functionSelector,
685
+ type: FunctionType.UTILITY,
686
+ hideMsgSender: false,
687
+ isStatic: false,
688
+ args,
689
+ returnTypes: [],
690
+ });
691
+
692
+ return this.executeUtilityCall(call, 'ALL_SCOPES');
665
693
  }
666
694
 
667
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
695
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes): Promise<Fr[]> {
668
696
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
669
697
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
670
698
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -677,23 +705,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
677
705
 
678
706
  try {
679
707
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
680
- const oracle = new UtilityExecutionOracle(
681
- call.to,
682
- [],
683
- [],
708
+ const oracle = new UtilityExecutionOracle({
709
+ contractAddress: call.to,
710
+ authWitnesses: [],
711
+ capsules: [],
684
712
  anchorBlockHeader,
685
- this.contractStore,
686
- this.noteStore,
687
- this.keyStore,
688
- this.addressStore,
689
- this.stateMachine.node,
690
- this.stateMachine.anchorBlockStore,
691
- this.recipientTaggingStore,
692
- this.senderAddressBookStore,
693
- this.capsuleStore,
694
- this.privateEventStore,
695
- this.jobId,
696
- );
713
+ contractStore: this.contractStore,
714
+ noteStore: this.noteStore,
715
+ keyStore: this.keyStore,
716
+ addressStore: this.addressStore,
717
+ aztecNode: this.stateMachine.node,
718
+ recipientTaggingStore: this.recipientTaggingStore,
719
+ senderAddressBookStore: this.senderAddressBookStore,
720
+ capsuleStore: this.capsuleStore,
721
+ privateEventStore: this.privateEventStore,
722
+ jobId: this.jobId,
723
+ scopes,
724
+ });
697
725
  const acirExecutionResult = await new WASMSimulator()
698
726
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
699
727
  .catch((err: Error) => {
@@ -709,10 +737,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
709
737
  );
710
738
  });
711
739
 
712
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
740
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
713
741
  return witnessMapToFields(acirExecutionResult.returnWitness);
714
742
  } catch (err) {
715
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
743
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
716
744
  }
717
745
  }
718
746