@aztec/txe 3.0.3 → 3.9.9-nightly.20260312

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 (75) hide show
  1. package/dest/constants.d.ts +3 -0
  2. package/dest/constants.d.ts.map +1 -0
  3. package/dest/constants.js +2 -0
  4. package/dest/index.d.ts +1 -1
  5. package/dest/index.d.ts.map +1 -1
  6. package/dest/index.js +85 -52
  7. package/dest/oracle/interfaces.d.ts +9 -6
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +4 -4
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +9 -11
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +21 -13
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +180 -72
  15. package/dest/rpc_translator.d.ts +29 -17
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +124 -57
  18. package/dest/state_machine/archiver.d.ts +20 -55
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +67 -108
  21. package/dest/state_machine/dummy_p2p_client.d.ts +20 -15
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +42 -25
  24. package/dest/state_machine/global_variable_builder.d.ts +4 -3
  25. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  26. package/dest/state_machine/global_variable_builder.js +13 -1
  27. package/dest/state_machine/index.d.ts +7 -7
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +41 -24
  30. package/dest/state_machine/mock_epoch_cache.d.ts +9 -6
  31. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  32. package/dest/state_machine/mock_epoch_cache.js +14 -7
  33. package/dest/state_machine/synchronizer.d.ts +3 -3
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/txe_session.d.ts +22 -11
  36. package/dest/txe_session.d.ts.map +1 -1
  37. package/dest/txe_session.js +154 -49
  38. package/dest/util/encoding.d.ts +617 -18
  39. package/dest/util/encoding.d.ts.map +1 -1
  40. package/dest/util/txe_account_store.d.ts +10 -0
  41. package/dest/util/txe_account_store.d.ts.map +1 -0
  42. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  43. package/dest/util/txe_public_contract_data_source.d.ts +5 -6
  44. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  45. package/dest/util/txe_public_contract_data_source.js +12 -29
  46. package/dest/utils/block_creation.d.ts +18 -4
  47. package/dest/utils/block_creation.d.ts.map +1 -1
  48. package/dest/utils/block_creation.js +37 -3
  49. package/dest/utils/tx_effect_creation.d.ts +2 -3
  50. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  51. package/dest/utils/tx_effect_creation.js +3 -6
  52. package/package.json +16 -16
  53. package/src/constants.ts +3 -0
  54. package/src/index.ts +97 -60
  55. package/src/oracle/interfaces.ts +11 -4
  56. package/src/oracle/txe_oracle_public_context.ts +9 -16
  57. package/src/oracle/txe_oracle_top_level_context.ts +223 -110
  58. package/src/rpc_translator.ts +141 -58
  59. package/src/state_machine/archiver.ts +61 -129
  60. package/src/state_machine/dummy_p2p_client.ts +58 -33
  61. package/src/state_machine/global_variable_builder.ts +19 -2
  62. package/src/state_machine/index.ts +61 -22
  63. package/src/state_machine/mock_epoch_cache.ts +15 -11
  64. package/src/state_machine/synchronizer.ts +2 -2
  65. package/src/txe_session.ts +213 -94
  66. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  67. package/src/util/txe_public_contract_data_source.ts +16 -42
  68. package/src/utils/block_creation.ts +47 -14
  69. package/src/utils/tx_effect_creation.ts +3 -11
  70. package/dest/util/txe_account_data_provider.d.ts +0 -10
  71. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  72. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  73. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  74. package/dest/util/txe_contract_data_provider.js +0 -22
  75. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -3,9 +3,8 @@ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
4
  import { PublicDataWrite } from '@aztec/stdlib/avm';
5
5
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
6
- import { Body, L2Block } from '@aztec/stdlib/block';
6
+ import type { L2Block } from '@aztec/stdlib/block';
7
7
  import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
8
- import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
9
8
  import {
10
9
  MerkleTreeId,
11
10
  type MerkleTreeWriteOperations,
@@ -14,7 +13,7 @@ import {
14
13
  } from '@aztec/stdlib/trees';
15
14
  import { GlobalVariables, TxEffect, TxHash } from '@aztec/stdlib/tx';
16
15
 
17
- import { insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from '../utils/block_creation.js';
16
+ import { insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
18
17
  import type { IAvmExecutionOracle } from './interfaces.js';
19
18
 
20
19
  export class TXEOraclePublicContext implements IAvmExecutionOracle {
@@ -79,13 +78,11 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
79
78
  this.transientUniqueNoteHashes.push(siloedNoteHash);
80
79
  }
81
80
 
82
- async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
83
- const nullifier = await siloNullifier(targetAddress, innerNullifier!);
84
-
81
+ async avmOpcodeNullifierExists(siloedNullifier: Fr): Promise<boolean> {
85
82
  const treeIndex = (
86
- await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()])
83
+ await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()])
87
84
  )[0];
88
- const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(nullifier));
85
+ const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(siloedNullifier));
89
86
 
90
87
  return treeIndex !== undefined || transientIndex !== undefined;
91
88
  }
@@ -102,8 +99,8 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
102
99
  ]);
103
100
  }
104
101
 
105
- async avmOpcodeStorageRead(slot: Fr): Promise<Fr> {
106
- const leafSlot = await computePublicDataTreeLeafSlot(this.contractAddress, slot);
102
+ async avmOpcodeStorageRead(slot: Fr, contractAddress: AztecAddress): Promise<Fr> {
103
+ const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
107
104
 
108
105
  const lowLeafResult = await this.forkedWorldTrees.getPreviousValueIndex(
109
106
  MerkleTreeId.PUBLIC_DATA_TREE,
@@ -120,7 +117,7 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
120
117
  )) as PublicDataTreeLeafPreimage
121
118
  ).leaf.value;
122
119
 
123
- this.logger.debug('AVM storage read', { slot, value });
120
+ this.logger.debug('AVM storage read', { slot, contractAddress, value });
124
121
 
125
122
  return value;
126
123
  }
@@ -133,11 +130,7 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
133
130
  const txEffect = this.makeTxEffect();
134
131
  await insertTxEffectIntoWorldTrees(txEffect, this.forkedWorldTrees);
135
132
 
136
- const block = new L2Block(
137
- makeAppendOnlyTreeSnapshot(),
138
- await makeTXEBlockHeader(this.forkedWorldTrees, this.globalVariables),
139
- new Body([txEffect]),
140
- );
133
+ const block = await makeTXEBlock(this.forkedWorldTrees, this.globalVariables, [txEffect]);
141
134
 
142
135
  await this.forkedWorldTrees.close();
143
136
 
@@ -12,10 +12,17 @@ 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
- AddressDataProvider,
17
+ AddressStore,
18
+ CapsuleStore,
19
+ type ContractStore,
20
+ NoteStore,
17
21
  ORACLE_VERSION,
18
- PXEOracleInterface,
22
+ PrivateEventStore,
23
+ RecipientTaggingStore,
24
+ SenderAddressBookStore,
25
+ SenderTaggingStore,
19
26
  enrichPublicSimulationError,
20
27
  } from '@aztec/pxe/server';
21
28
  import {
@@ -44,11 +51,10 @@ import {
44
51
  PublicContractsDB,
45
52
  PublicProcessor,
46
53
  } from '@aztec/simulator/server';
47
- import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
54
+ import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
48
55
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
49
56
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
50
57
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
51
- import { Body, L2Block } from '@aztec/stdlib/block';
52
58
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
53
59
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
54
60
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
@@ -59,7 +65,7 @@ import {
59
65
  PublicCallRequest,
60
66
  } from '@aztec/stdlib/kernel';
61
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
62
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
68
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
63
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
64
70
  import {
65
71
  CallContext,
@@ -76,15 +82,11 @@ import {
76
82
  import type { UInt64 } from '@aztec/stdlib/types';
77
83
  import { ForkCheckpoint } from '@aztec/world-state';
78
84
 
85
+ import { DEFAULT_ADDRESS } from '../constants.js';
79
86
  import type { TXEStateMachine } from '../state_machine/index.js';
80
- import type { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
81
- import type { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
87
+ import type { TXEAccountStore } from '../util/txe_account_store.js';
82
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
83
- import {
84
- getSingleTxBlockRequestHash,
85
- insertTxEffectIntoWorldTrees,
86
- makeTXEBlockHeader,
87
- } from '../utils/block_creation.js';
89
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
88
90
  import type { ITxeExecutionOracle } from './interfaces.js';
89
91
 
90
92
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -95,11 +97,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
95
97
 
96
98
  constructor(
97
99
  private stateMachine: TXEStateMachine,
98
- private contractDataProvider: TXEContractDataProvider,
100
+ private contractStore: ContractStore,
101
+ private noteStore: NoteStore,
99
102
  private keyStore: KeyStore,
100
- private addressDataProvider: AddressDataProvider,
101
- private accountDataProvider: TXEAccountDataProvider,
102
- private pxeOracleInterface: PXEOracleInterface,
103
+ private addressStore: AddressStore,
104
+ private accountStore: TXEAccountStore,
105
+ private senderTaggingStore: SenderTaggingStore,
106
+ private recipientTaggingStore: RecipientTaggingStore,
107
+ private senderAddressBookStore: SenderAddressBookStore,
108
+ private capsuleStore: CapsuleStore,
109
+ private privateEventStore: PrivateEventStore,
103
110
  private nextBlockTimestamp: bigint,
104
111
  private version: Fr,
105
112
  private chainId: Fr,
@@ -124,13 +131,18 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
124
131
  }
125
132
 
126
133
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
127
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
134
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
128
135
  if (!LogLevels[level]) {
129
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
130
137
  }
131
138
  const levelName = LogLevels[level];
132
139
 
133
140
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
141
+ return Promise.resolve();
142
+ }
143
+
144
+ txeGetDefaultAddress(): AztecAddress {
145
+ return DEFAULT_ADDRESS;
134
146
  }
135
147
 
136
148
  async txeGetNextBlockNumber(): Promise<BlockNumber> {
@@ -146,7 +158,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
146
158
  }
147
159
 
148
160
  async txeGetLastTxEffects() {
149
- const block = await this.stateMachine.archiver.getBlock('latest');
161
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
162
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
150
163
 
151
164
  if (block!.body.txEffects.length != 1) {
152
165
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -158,6 +171,36 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
158
171
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
159
172
  }
160
173
 
174
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
175
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
176
+ this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
177
+ return;
178
+ }
179
+
180
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
181
+ await this.stateMachine.contractSyncService.ensureContractSynced(
182
+ contractAddress,
183
+ null,
184
+ async (call, execScopes) => {
185
+ await this.executeUtilityCall(call, execScopes, jobId);
186
+ },
187
+ blockHeader,
188
+ jobId,
189
+ [scope],
190
+ );
191
+ }
192
+
193
+ async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
194
+ return (
195
+ await this.privateEventStore.getPrivateEvents(selector, {
196
+ contractAddress,
197
+ scopes: [scope],
198
+ fromBlock: 0,
199
+ toBlock: (await this.getLastBlockNumber()) + 1,
200
+ })
201
+ ).map(e => e.packedEvent);
202
+ }
203
+
161
204
  async txeAdvanceBlocksBy(blocks: number) {
162
205
  this.logger.debug(`time traveling ${blocks} blocks`);
163
206
 
@@ -185,8 +228,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
185
228
  if (!secret.equals(Fr.ZERO)) {
186
229
  await this.txeAddAccount(artifact, instance, secret);
187
230
  } else {
188
- await this.contractDataProvider.addContractInstance(instance);
189
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
231
+ await this.contractStore.addContractInstance(instance);
232
+ await this.contractStore.addContractArtifact(artifact);
190
233
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
191
234
  }
192
235
  }
@@ -195,29 +238,29 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
195
238
  const partialAddress = await computePartialAddress(instance);
196
239
 
197
240
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
198
- await this.contractDataProvider.addContractInstance(instance);
199
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
241
+ await this.contractStore.addContractInstance(instance);
242
+ await this.contractStore.addContractArtifact(artifact);
200
243
 
201
244
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
202
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
203
- await this.addressDataProvider.addCompleteAddress(completeAddress);
245
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
246
+ await this.addressStore.addCompleteAddress(completeAddress);
204
247
  this.logger.debug(`Created account ${completeAddress.address}`);
205
248
 
206
249
  return completeAddress;
207
250
  }
208
251
 
209
252
  async txeCreateAccount(secret: Fr) {
210
- // This is a footgun !
253
+ // This is a foot gun !
211
254
  const completeAddress = await this.keyStore.addAccount(secret, secret);
212
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
213
- await this.addressDataProvider.addCompleteAddress(completeAddress);
255
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
256
+ await this.addressStore.addCompleteAddress(completeAddress);
214
257
  this.logger.debug(`Created account ${completeAddress.address}`);
215
258
 
216
259
  return completeAddress;
217
260
  }
218
261
 
219
262
  async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
220
- const account = await this.accountDataProvider.getAccount(address);
263
+ const account = await this.accountStore.getAccount(address);
221
264
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
222
265
 
223
266
  const schnorr = new Schnorr();
@@ -238,19 +281,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
238
281
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
239
282
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
240
283
 
241
- const block = new L2Block(
242
- makeAppendOnlyTreeSnapshot(),
243
- await makeTXEBlockHeader(
244
- forkedWorldTrees,
245
- makeGlobalVariables(undefined, {
246
- blockNumber,
247
- timestamp: this.nextBlockTimestamp,
248
- version: this.version,
249
- chainId: this.chainId,
250
- }),
251
- ),
252
- new Body([txEffect]),
253
- );
284
+ const globals = makeGlobalVariables(undefined, {
285
+ blockNumber,
286
+ timestamp: this.nextBlockTimestamp,
287
+ version: this.version,
288
+ chainId: this.chainId,
289
+ });
290
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
254
291
 
255
292
  await forkedWorldTrees.close();
256
293
 
@@ -266,12 +303,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
266
303
  args: Fr[],
267
304
  argsHash: Fr = Fr.zero(),
268
305
  isStaticCall: boolean = false,
306
+ jobId: string,
269
307
  ) {
270
308
  this.logger.verbose(
271
- `Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
309
+ `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
272
310
  );
273
311
 
274
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
312
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
275
313
  if (!artifact) {
276
314
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
277
315
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -279,51 +317,77 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
279
317
  throw new Error(message);
280
318
  }
281
319
 
320
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
321
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
322
+ const effectiveScopes = from.isZero() ? [] : [from];
323
+
324
+ // Sync notes before executing private function to discover notes from previous transactions
325
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
326
+ await this.executeUtilityCall(call, execScopes, jobId);
327
+ };
328
+
329
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
330
+ await this.stateMachine.contractSyncService.ensureContractSynced(
331
+ targetContractAddress,
332
+ functionSelector,
333
+ utilityExecutor,
334
+ blockHeader,
335
+ jobId,
336
+ effectiveScopes,
337
+ );
338
+
282
339
  const blockNumber = await this.txeGetNextBlockNumber();
283
340
 
284
341
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
285
342
 
286
343
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
287
-
288
344
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
289
-
290
345
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
291
346
 
292
347
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
293
348
 
294
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
295
-
296
349
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
297
350
  const noteCache = new ExecutionNoteCache(protocolNullifier);
351
+ // In production, the account contract sets the min revertible counter before calling the app function.
352
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
353
+ // marking all side effects as revertible.
354
+ const minRevertibleSideEffectCounter = 1;
355
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
298
356
  const taggingIndexCache = new ExecutionTaggingIndexCache();
299
357
 
300
358
  const simulator = new WASMSimulator();
301
359
 
302
- const privateExecutionOracle = new PrivateExecutionOracle(
360
+ const privateExecutionOracle = new PrivateExecutionOracle({
303
361
  argsHash,
304
362
  txContext,
305
363
  callContext,
306
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
307
- blockHeader,
308
- /** List of transient auth witnesses to be used during this simulation */
309
- Array.from(this.authwits.values()),
310
- /** List of transient auth witnesses to be used during this simulation */
311
- [],
312
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
364
+ anchorBlockHeader: blockHeader,
365
+ utilityExecutor,
366
+ authWitnesses: Array.from(this.authwits.values()),
367
+ capsules: [],
368
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
313
369
  noteCache,
314
370
  taggingIndexCache,
315
- this.pxeOracleInterface,
316
- 0,
317
- 1,
318
- undefined, // log
319
- undefined, // scopes
320
- /**
321
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
322
- * contract would perform, including setting senderForTags.
323
- */
324
- from,
371
+ contractStore: this.contractStore,
372
+ noteStore: this.noteStore,
373
+ keyStore: this.keyStore,
374
+ addressStore: this.addressStore,
375
+ aztecNode: this.stateMachine.node,
376
+ senderTaggingStore: this.senderTaggingStore,
377
+ recipientTaggingStore: this.recipientTaggingStore,
378
+ senderAddressBookStore: this.senderAddressBookStore,
379
+ capsuleStore: this.capsuleStore,
380
+ privateEventStore: this.privateEventStore,
381
+ contractSyncService: this.stateMachine.contractSyncService,
382
+ jobId,
383
+ totalPublicCalldataCount: 0,
384
+ sideEffectCounter: minRevertibleSideEffectCounter,
385
+ scopes: effectiveScopes,
386
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
387
+ // contract would perform, including setting senderForTags.
388
+ senderForTags: from,
325
389
  simulator,
326
- );
390
+ });
327
391
 
328
392
  // 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.
329
393
  let result: PrivateExecutionResult;
@@ -350,19 +414,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
350
414
  }),
351
415
  );
352
416
 
353
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
354
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
355
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
356
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
417
+ noteCache.finish();
418
+ const nonceGenerator = noteCache.getNonceGenerator();
419
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
357
420
  } catch (err) {
358
421
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
359
422
  }
360
423
 
361
- // According to the protocol rules, the nonce generator for the note hashes
362
- // can either be the first nullifier in the tx or the hash of the initial tx request
363
- // if there are none.
364
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
365
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
424
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
425
+ // the nonce generator for the note hashes.
426
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
427
+ const { publicInputs } = await generateSimulatedProvingResult(
428
+ result,
429
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
430
+ this.stateMachine.node,
431
+ minRevertibleSideEffectCounter,
432
+ );
366
433
 
367
434
  const globals = makeGlobalVariables();
368
435
  globals.blockNumber = blockNumber;
@@ -373,7 +440,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
373
440
 
374
441
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
375
442
 
376
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
443
+ const bindings = this.logger.getBindings();
444
+ const contractsDB = new PublicContractsDB(
445
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
446
+ bindings,
447
+ );
377
448
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
378
449
  const config = PublicSimulatorConfig.from({
379
450
  skipFeeEnforcement: true,
@@ -386,8 +457,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
386
457
  globals,
387
458
  guardedMerkleTrees,
388
459
  contractsDB,
389
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
460
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
390
461
  new TestDateProvider(),
462
+ undefined,
463
+ createLogger('simulator:public-processor', bindings),
391
464
  );
392
465
 
393
466
  const tx = await Tx.create({
@@ -412,7 +485,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
412
485
  } else if (!processedTx.revertCode.isOK()) {
413
486
  if (processedTx.revertReason) {
414
487
  try {
415
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
488
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
416
489
  // eslint-disable-next-line no-empty
417
490
  } catch {}
418
491
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -441,13 +514,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
441
514
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
442
515
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
443
516
 
444
- const body = new Body([txEffect]);
445
-
446
- const l2Block = new L2Block(
447
- makeAppendOnlyTreeSnapshot(),
448
- await makeTXEBlockHeader(forkedWorldTrees, globals),
449
- body,
450
- );
517
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
451
518
 
452
519
  await this.stateMachine.handleL2Block(l2Block);
453
520
 
@@ -463,7 +530,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
463
530
  isStaticCall: boolean,
464
531
  ) {
465
532
  this.logger.verbose(
466
- `Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
533
+ `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
467
534
  );
468
535
 
469
536
  const blockNumber = await this.txeGetNextBlockNumber();
@@ -476,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
476
543
 
477
544
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
478
545
 
479
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
546
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
480
547
 
481
548
  const calldataHash = await computeCalldataHash(calldata);
482
549
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -490,7 +557,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
490
557
 
491
558
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
492
559
 
493
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
560
+ const bindings2 = this.logger.getBindings();
561
+ const contractsDB = new PublicContractsDB(
562
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
563
+ bindings2,
564
+ );
494
565
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
495
566
  const config = PublicSimulatorConfig.from({
496
567
  skipFeeEnforcement: true,
@@ -499,8 +570,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
499
570
  collectStatistics: false,
500
571
  collectCallMetadata: true,
501
572
  });
502
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
503
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
573
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
574
+ const processor = new PublicProcessor(
575
+ globals,
576
+ guardedMerkleTrees,
577
+ contractsDB,
578
+ simulator,
579
+ new TestDateProvider(),
580
+ undefined,
581
+ createLogger('simulator:public-processor', bindings2),
582
+ );
504
583
 
505
584
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
506
585
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -531,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
531
610
  constantData,
532
611
  /*gasUsed=*/ new Gas(0, 0),
533
612
  /*feePayer=*/ AztecAddress.zero(),
534
- /*includeByTimestamp=*/ 0n,
613
+ /*expirationTimestamp=*/ 0n,
535
614
  inputsForPublic,
536
615
  undefined,
537
616
  );
@@ -558,7 +637,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
558
637
  } else if (!processedTx.revertCode.isOK()) {
559
638
  if (processedTx.revertReason) {
560
639
  try {
561
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
640
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
562
641
  // eslint-disable-next-line no-empty
563
642
  } catch {}
564
643
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -590,13 +669,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
590
669
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
591
670
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
592
671
 
593
- const body = new Body([txEffect]);
594
-
595
- const l2Block = new L2Block(
596
- makeAppendOnlyTreeSnapshot(),
597
- await makeTXEBlockHeader(forkedWorldTrees, globals),
598
- body,
599
- );
672
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
600
673
 
601
674
  await this.stateMachine.handleL2Block(l2Block);
602
675
 
@@ -605,23 +678,46 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
605
678
  return returnValues ?? [];
606
679
  }
607
680
 
608
- async txeSimulateUtilityFunction(
681
+ async txeExecuteUtilityFunction(
609
682
  targetContractAddress: AztecAddress,
610
683
  functionSelector: FunctionSelector,
611
684
  args: Fr[],
685
+ jobId: string,
612
686
  ) {
613
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
687
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
614
688
  if (!artifact) {
615
689
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
616
690
  }
617
691
 
618
- const call = {
692
+ // Sync notes before executing utility function to discover notes from previous transactions
693
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
694
+ await this.stateMachine.contractSyncService.ensureContractSynced(
695
+ targetContractAddress,
696
+ functionSelector,
697
+ async (call, execScopes) => {
698
+ await this.executeUtilityCall(call, execScopes, jobId);
699
+ },
700
+ blockHeader,
701
+ jobId,
702
+ 'ALL_SCOPES',
703
+ );
704
+
705
+ const call = FunctionCall.from({
619
706
  name: artifact.name,
620
- selector: functionSelector,
621
707
  to: targetContractAddress,
622
- };
708
+ selector: functionSelector,
709
+ type: FunctionType.UTILITY,
710
+ hideMsgSender: false,
711
+ isStatic: false,
712
+ args,
713
+ returnTypes: [],
714
+ });
715
+
716
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
717
+ }
623
718
 
624
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
719
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
720
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
625
721
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
626
722
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
627
723
  }
@@ -632,9 +728,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
632
728
  });
633
729
 
634
730
  try {
635
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
731
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
732
+ const oracle = new UtilityExecutionOracle({
733
+ contractAddress: call.to,
734
+ authWitnesses: [],
735
+ capsules: [],
736
+ anchorBlockHeader,
737
+ contractStore: this.contractStore,
738
+ noteStore: this.noteStore,
739
+ keyStore: this.keyStore,
740
+ addressStore: this.addressStore,
741
+ aztecNode: this.stateMachine.node,
742
+ recipientTaggingStore: this.recipientTaggingStore,
743
+ senderAddressBookStore: this.senderAddressBookStore,
744
+ capsuleStore: this.capsuleStore,
745
+ privateEventStore: this.privateEventStore,
746
+ jobId,
747
+ scopes,
748
+ });
636
749
  const acirExecutionResult = await new WASMSimulator()
637
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
750
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
638
751
  .catch((err: Error) => {
639
752
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
640
753
  throw new ExecutionError(
@@ -648,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
648
761
  );
649
762
  });
650
763
 
651
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
764
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
652
765
  return witnessMapToFields(acirExecutionResult.returnWitness);
653
766
  } catch (err) {
654
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
767
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
655
768
  }
656
769
  }
657
770