@aztec/txe 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c

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 (78) 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 +12 -9
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +10 -12
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +23 -14
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +177 -79
  15. package/dest/rpc_translator.d.ts +30 -18
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +127 -60
  18. package/dest/state_machine/archiver.d.ts +21 -52
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +63 -94
  21. package/dest/state_machine/dummy_p2p_client.d.ts +19 -14
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +41 -24
  24. package/dest/state_machine/global_variable_builder.d.ts +6 -5
  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 +40 -23
  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 -2
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/state_machine/synchronizer.js +5 -4
  36. package/dest/txe_session.d.ts +21 -15
  37. package/dest/txe_session.d.ts.map +1 -1
  38. package/dest/txe_session.js +151 -52
  39. package/dest/util/encoding.d.ts +618 -19
  40. package/dest/util/encoding.d.ts.map +1 -1
  41. package/dest/util/encoding.js +1 -1
  42. package/dest/util/txe_account_store.d.ts +10 -0
  43. package/dest/util/txe_account_store.d.ts.map +1 -0
  44. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  45. package/dest/util/txe_public_contract_data_source.d.ts +8 -8
  46. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  47. package/dest/util/txe_public_contract_data_source.js +12 -29
  48. package/dest/utils/block_creation.d.ts +21 -6
  49. package/dest/utils/block_creation.d.ts.map +1 -1
  50. package/dest/utils/block_creation.js +38 -4
  51. package/dest/utils/tx_effect_creation.d.ts +3 -3
  52. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  53. package/dest/utils/tx_effect_creation.js +4 -7
  54. package/package.json +18 -18
  55. package/src/constants.ts +3 -0
  56. package/src/index.ts +97 -60
  57. package/src/oracle/interfaces.ts +11 -8
  58. package/src/oracle/txe_oracle_public_context.ts +12 -19
  59. package/src/oracle/txe_oracle_top_level_context.ts +213 -124
  60. package/src/rpc_translator.ts +156 -60
  61. package/src/state_machine/archiver.ts +59 -114
  62. package/src/state_machine/dummy_p2p_client.ts +57 -32
  63. package/src/state_machine/global_variable_builder.ts +21 -4
  64. package/src/state_machine/index.ts +60 -21
  65. package/src/state_machine/mock_epoch_cache.ts +15 -11
  66. package/src/state_machine/synchronizer.ts +6 -5
  67. package/src/txe_session.ts +207 -100
  68. package/src/util/encoding.ts +1 -1
  69. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  70. package/src/util/txe_public_contract_data_source.ts +20 -45
  71. package/src/utils/block_creation.ts +49 -15
  72. package/src/utils/tx_effect_creation.ts +5 -12
  73. package/dest/util/txe_account_data_provider.d.ts +0 -10
  74. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  75. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  76. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  77. package/dest/util/txe_contract_data_provider.js +0 -22
  78. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -6,15 +6,23 @@ import {
6
6
  DEFAULT_TEARDOWN_L2_GAS_LIMIT,
7
7
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
8
8
  } from '@aztec/constants';
9
- import { Schnorr } from '@aztec/foundation/crypto';
10
- import { Fr } from '@aztec/foundation/fields';
9
+ import { BlockNumber } from '@aztec/foundation/branded-types';
10
+ import { Schnorr } from '@aztec/foundation/crypto/schnorr';
11
+ import { Fr } from '@aztec/foundation/curves/bn254';
11
12
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
12
13
  import { TestDateProvider } from '@aztec/foundation/timer';
13
14
  import type { KeyStore } from '@aztec/key-store';
15
+ import type { AccessScopes } from '@aztec/pxe/client/lazy';
14
16
  import {
15
- AddressDataProvider,
17
+ AddressStore,
18
+ CapsuleStore,
19
+ type ContractStore,
20
+ NoteStore,
16
21
  ORACLE_VERSION,
17
- PXEOracleInterface,
22
+ PrivateEventStore,
23
+ RecipientTaggingStore,
24
+ SenderAddressBookStore,
25
+ SenderTaggingStore,
18
26
  enrichPublicSimulationError,
19
27
  } from '@aztec/pxe/server';
20
28
  import {
@@ -38,16 +46,15 @@ import {
38
46
  witnessMapToFields,
39
47
  } from '@aztec/simulator/client';
40
48
  import {
49
+ CppPublicTxSimulator,
41
50
  GuardedMerkleTreeOperations,
42
51
  PublicContractsDB,
43
52
  PublicProcessor,
44
- PublicTxSimulator,
45
53
  } from '@aztec/simulator/server';
46
- import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
54
+ import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
47
55
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
48
56
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
49
57
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
50
- import { Body, L2Block } from '@aztec/stdlib/block';
51
58
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
52
59
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
53
60
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
@@ -58,7 +65,7 @@ import {
58
65
  PublicCallRequest,
59
66
  } from '@aztec/stdlib/kernel';
60
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
61
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
68
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
62
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
63
70
  import {
64
71
  CallContext,
@@ -75,15 +82,11 @@ import {
75
82
  import type { UInt64 } from '@aztec/stdlib/types';
76
83
  import { ForkCheckpoint } from '@aztec/world-state';
77
84
 
85
+ import { DEFAULT_ADDRESS } from '../constants.js';
78
86
  import type { TXEStateMachine } from '../state_machine/index.js';
79
- import type { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
80
- import type { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
87
+ import type { TXEAccountStore } from '../util/txe_account_store.js';
81
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
82
- import {
83
- getSingleTxBlockRequestHash,
84
- insertTxEffectIntoWorldTrees,
85
- makeTXEBlockHeader,
86
- } from '../utils/block_creation.js';
89
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
87
90
  import type { ITxeExecutionOracle } from './interfaces.js';
88
91
 
89
92
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -94,11 +97,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
94
97
 
95
98
  constructor(
96
99
  private stateMachine: TXEStateMachine,
97
- private contractDataProvider: TXEContractDataProvider,
100
+ private contractStore: ContractStore,
101
+ private noteStore: NoteStore,
98
102
  private keyStore: KeyStore,
99
- private addressDataProvider: AddressDataProvider,
100
- private accountDataProvider: TXEAccountDataProvider,
101
- 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,
110
+ private jobId: string,
102
111
  private nextBlockTimestamp: bigint,
103
112
  private version: Fr,
104
113
  private chainId: Fr,
@@ -123,17 +132,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
123
132
  }
124
133
 
125
134
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
126
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
135
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
127
136
  if (!LogLevels[level]) {
128
- throw new Error(`Invalid debug log level: ${level}`);
137
+ throw new Error(`Invalid log level: ${level}`);
129
138
  }
130
139
  const levelName = LogLevels[level];
131
140
 
132
141
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
142
+ return Promise.resolve();
143
+ }
144
+
145
+ txeGetDefaultAddress(): AztecAddress {
146
+ return DEFAULT_ADDRESS;
133
147
  }
134
148
 
135
- async txeGetNextBlockNumber(): Promise<number> {
136
- return (await this.getLastBlockNumber()) + 1;
149
+ async txeGetNextBlockNumber(): Promise<BlockNumber> {
150
+ return BlockNumber((await this.getLastBlockNumber()) + 1);
137
151
  }
138
152
 
139
153
  txeGetNextBlockTimestamp(): Promise<bigint> {
@@ -145,7 +159,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
145
159
  }
146
160
 
147
161
  async txeGetLastTxEffects() {
148
- const block = await this.stateMachine.archiver.getBlock('latest');
162
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
163
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
149
164
 
150
165
  if (block!.body.txEffects.length != 1) {
151
166
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -157,6 +172,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
157
172
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
158
173
  }
159
174
 
175
+ async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
176
+ return (
177
+ await this.privateEventStore.getPrivateEvents(selector, {
178
+ contractAddress,
179
+ scopes: [scope],
180
+ fromBlock: 0,
181
+ toBlock: (await this.getLastBlockNumber()) + 1,
182
+ })
183
+ ).map(e => e.packedEvent);
184
+ }
185
+
160
186
  async txeAdvanceBlocksBy(blocks: number) {
161
187
  this.logger.debug(`time traveling ${blocks} blocks`);
162
188
 
@@ -184,8 +210,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
184
210
  if (!secret.equals(Fr.ZERO)) {
185
211
  await this.txeAddAccount(artifact, instance, secret);
186
212
  } else {
187
- await this.contractDataProvider.addContractInstance(instance);
188
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
213
+ await this.contractStore.addContractInstance(instance);
214
+ await this.contractStore.addContractArtifact(artifact);
189
215
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
190
216
  }
191
217
  }
@@ -194,29 +220,29 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
194
220
  const partialAddress = await computePartialAddress(instance);
195
221
 
196
222
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
197
- await this.contractDataProvider.addContractInstance(instance);
198
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
223
+ await this.contractStore.addContractInstance(instance);
224
+ await this.contractStore.addContractArtifact(artifact);
199
225
 
200
226
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
201
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
202
- await this.addressDataProvider.addCompleteAddress(completeAddress);
227
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
228
+ await this.addressStore.addCompleteAddress(completeAddress);
203
229
  this.logger.debug(`Created account ${completeAddress.address}`);
204
230
 
205
231
  return completeAddress;
206
232
  }
207
233
 
208
234
  async txeCreateAccount(secret: Fr) {
209
- // This is a footgun !
235
+ // This is a foot gun !
210
236
  const completeAddress = await this.keyStore.addAccount(secret, secret);
211
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
212
- await this.addressDataProvider.addCompleteAddress(completeAddress);
237
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
238
+ await this.addressStore.addCompleteAddress(completeAddress);
213
239
  this.logger.debug(`Created account ${completeAddress.address}`);
214
240
 
215
241
  return completeAddress;
216
242
  }
217
243
 
218
244
  async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
219
- const account = await this.accountDataProvider.getAccount(address);
245
+ const account = await this.accountStore.getAccount(address);
220
246
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
221
247
 
222
248
  const schnorr = new Schnorr();
@@ -237,19 +263,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
237
263
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
238
264
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
239
265
 
240
- const block = new L2Block(
241
- makeAppendOnlyTreeSnapshot(),
242
- await makeTXEBlockHeader(
243
- forkedWorldTrees,
244
- makeGlobalVariables(undefined, {
245
- blockNumber,
246
- timestamp: this.nextBlockTimestamp,
247
- version: this.version,
248
- chainId: this.chainId,
249
- }),
250
- ),
251
- new Body([txEffect]),
252
- );
266
+ const globals = makeGlobalVariables(undefined, {
267
+ blockNumber,
268
+ timestamp: this.nextBlockTimestamp,
269
+ version: this.version,
270
+ chainId: this.chainId,
271
+ });
272
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
253
273
 
254
274
  await forkedWorldTrees.close();
255
275
 
@@ -267,10 +287,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
267
287
  isStaticCall: boolean = false,
268
288
  ) {
269
289
  this.logger.verbose(
270
- `Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
290
+ `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
271
291
  );
272
292
 
273
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
293
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
274
294
  if (!artifact) {
275
295
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
276
296
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -278,51 +298,77 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
278
298
  throw new Error(message);
279
299
  }
280
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
+
305
+ // Sync notes before executing private function to discover notes from previous transactions
306
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
307
+ await this.executeUtilityCall(call, execScopes);
308
+ };
309
+
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
+ );
319
+
281
320
  const blockNumber = await this.txeGetNextBlockNumber();
282
321
 
283
322
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
284
323
 
285
324
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
286
-
287
325
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
288
-
289
326
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
290
327
 
291
328
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
292
329
 
293
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
294
-
295
330
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
296
331
  const noteCache = new ExecutionNoteCache(protocolNullifier);
332
+ // In production, the account contract sets the min revertible counter before calling the app function.
333
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
334
+ // marking all side effects as revertible.
335
+ const minRevertibleSideEffectCounter = 1;
336
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
297
337
  const taggingIndexCache = new ExecutionTaggingIndexCache();
298
338
 
299
339
  const simulator = new WASMSimulator();
300
340
 
301
- const privateExecutionOracle = new PrivateExecutionOracle(
341
+ const privateExecutionOracle = new PrivateExecutionOracle({
302
342
  argsHash,
303
343
  txContext,
304
344
  callContext,
305
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
306
- blockHeader,
307
- /** List of transient auth witnesses to be used during this simulation */
308
- Array.from(this.authwits.values()),
309
- /** List of transient auth witnesses to be used during this simulation */
310
- [],
311
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
345
+ anchorBlockHeader: blockHeader,
346
+ utilityExecutor,
347
+ authWitnesses: Array.from(this.authwits.values()),
348
+ capsules: [],
349
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
312
350
  noteCache,
313
351
  taggingIndexCache,
314
- this.pxeOracleInterface,
315
- 0,
316
- 1,
317
- undefined, // log
318
- undefined, // scopes
319
- /**
320
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
321
- * contract would perform, including setting senderForTags.
322
- */
323
- 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,
324
370
  simulator,
325
- );
371
+ });
326
372
 
327
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.
328
374
  let result: PrivateExecutionResult;
@@ -349,19 +395,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
349
395
  }),
350
396
  );
351
397
 
352
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
353
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
354
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
355
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
398
+ noteCache.finish();
399
+ const nonceGenerator = noteCache.getNonceGenerator();
400
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
356
401
  } catch (err) {
357
402
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
358
403
  }
359
404
 
360
- // According to the protocol rules, the nonce generator for the note hashes
361
- // can either be the first nullifier in the tx or the hash of the initial tx request
362
- // if there are none.
363
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
364
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
405
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
406
+ // the nonce generator for the note hashes.
407
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
408
+ const { publicInputs } = await generateSimulatedProvingResult(
409
+ result,
410
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
411
+ this.stateMachine.node,
412
+ minRevertibleSideEffectCounter,
413
+ );
365
414
 
366
415
  const globals = makeGlobalVariables();
367
416
  globals.blockNumber = blockNumber;
@@ -372,7 +421,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
372
421
 
373
422
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
374
423
 
375
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
424
+ const bindings = this.logger.getBindings();
425
+ const contractsDB = new PublicContractsDB(
426
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
427
+ bindings,
428
+ );
376
429
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
377
430
  const config = PublicSimulatorConfig.from({
378
431
  skipFeeEnforcement: true,
@@ -385,8 +438,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
385
438
  globals,
386
439
  guardedMerkleTrees,
387
440
  contractsDB,
388
- new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
441
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
389
442
  new TestDateProvider(),
443
+ undefined,
444
+ createLogger('simulator:public-processor', bindings),
390
445
  );
391
446
 
392
447
  const tx = await Tx.create({
@@ -411,7 +466,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
411
466
  } else if (!processedTx.revertCode.isOK()) {
412
467
  if (processedTx.revertReason) {
413
468
  try {
414
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
469
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
415
470
  // eslint-disable-next-line no-empty
416
471
  } catch {}
417
472
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -440,13 +495,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
440
495
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
441
496
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
442
497
 
443
- const body = new Body([txEffect]);
444
-
445
- const l2Block = new L2Block(
446
- makeAppendOnlyTreeSnapshot(),
447
- await makeTXEBlockHeader(forkedWorldTrees, globals),
448
- body,
449
- );
498
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
450
499
 
451
500
  await this.stateMachine.handleL2Block(l2Block);
452
501
 
@@ -462,7 +511,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
462
511
  isStaticCall: boolean,
463
512
  ) {
464
513
  this.logger.verbose(
465
- `Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
514
+ `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
466
515
  );
467
516
 
468
517
  const blockNumber = await this.txeGetNextBlockNumber();
@@ -475,7 +524,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
475
524
 
476
525
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
477
526
 
478
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
527
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
479
528
 
480
529
  const calldataHash = await computeCalldataHash(calldata);
481
530
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -489,7 +538,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
489
538
 
490
539
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
491
540
 
492
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
541
+ const bindings2 = this.logger.getBindings();
542
+ const contractsDB = new PublicContractsDB(
543
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
544
+ bindings2,
545
+ );
493
546
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
494
547
  const config = PublicSimulatorConfig.from({
495
548
  skipFeeEnforcement: true,
@@ -498,17 +551,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
498
551
  collectStatistics: false,
499
552
  collectCallMetadata: true,
500
553
  });
501
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
502
- 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
+ );
503
564
 
504
565
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
505
566
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
506
567
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
507
568
  // unique.
508
569
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
509
- if (!isStaticCall) {
510
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
511
- }
570
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
512
571
 
513
572
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
514
573
  // may require producing reverts.
@@ -532,7 +591,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
532
591
  constantData,
533
592
  /*gasUsed=*/ new Gas(0, 0),
534
593
  /*feePayer=*/ AztecAddress.zero(),
535
- /*includeByTimestamp=*/ 0n,
594
+ /*expirationTimestamp=*/ 0n,
536
595
  inputsForPublic,
537
596
  undefined,
538
597
  );
@@ -559,7 +618,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
559
618
  } else if (!processedTx.revertCode.isOK()) {
560
619
  if (processedTx.revertReason) {
561
620
  try {
562
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
621
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
563
622
  // eslint-disable-next-line no-empty
564
623
  } catch {}
565
624
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -591,13 +650,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
591
650
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
592
651
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
593
652
 
594
- const body = new Body([txEffect]);
595
-
596
- const l2Block = new L2Block(
597
- makeAppendOnlyTreeSnapshot(),
598
- await makeTXEBlockHeader(forkedWorldTrees, globals),
599
- body,
600
- );
653
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
601
654
 
602
655
  await this.stateMachine.handleL2Block(l2Block);
603
656
 
@@ -606,23 +659,41 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
606
659
  return returnValues ?? [];
607
660
  }
608
661
 
609
- async txeSimulateUtilityFunction(
610
- targetContractAddress: AztecAddress,
611
- functionSelector: FunctionSelector,
612
- args: Fr[],
613
- ) {
614
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
662
+ async txeExecuteUtilityFunction(targetContractAddress: AztecAddress, functionSelector: FunctionSelector, args: Fr[]) {
663
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
615
664
  if (!artifact) {
616
665
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
617
666
  }
618
667
 
619
- const call = {
668
+ // Sync notes before executing utility function to discover notes from previous transactions
669
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
670
+ await this.stateMachine.contractSyncService.ensureContractSynced(
671
+ targetContractAddress,
672
+ functionSelector,
673
+ async (call, execScopes) => {
674
+ await this.executeUtilityCall(call, execScopes);
675
+ },
676
+ blockHeader,
677
+ this.jobId,
678
+ 'ALL_SCOPES',
679
+ );
680
+
681
+ const call = FunctionCall.from({
620
682
  name: artifact.name,
621
- selector: functionSelector,
622
683
  to: targetContractAddress,
623
- };
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');
693
+ }
624
694
 
625
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
695
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes): Promise<Fr[]> {
696
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
626
697
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
627
698
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
628
699
  }
@@ -633,9 +704,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
633
704
  });
634
705
 
635
706
  try {
636
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
707
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
708
+ const oracle = new UtilityExecutionOracle({
709
+ contractAddress: call.to,
710
+ authWitnesses: [],
711
+ capsules: [],
712
+ anchorBlockHeader,
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
+ });
637
725
  const acirExecutionResult = await new WASMSimulator()
638
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
726
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
639
727
  .catch((err: Error) => {
640
728
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
641
729
  throw new ExecutionError(
@@ -649,10 +737,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
649
737
  );
650
738
  });
651
739
 
652
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
740
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
653
741
  return witnessMapToFields(acirExecutionResult.returnWitness);
654
742
  } catch (err) {
655
- 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'));
656
744
  }
657
745
  }
658
746
 
@@ -661,7 +749,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
661
749
  return [this.nextBlockTimestamp, this.authwits];
662
750
  }
663
751
 
664
- private async getLastBlockNumber(): Promise<number> {
665
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
752
+ private async getLastBlockNumber(): Promise<BlockNumber> {
753
+ const header = await this.stateMachine.node.getBlockHeader('latest');
754
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
666
755
  }
667
756
  }