@aztec/txe 0.0.1-commit.b655e406 → 0.0.1-commit.c0b82b2

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 (81) hide show
  1. package/dest/bin/index.d.ts +1 -1
  2. package/dest/constants.d.ts +3 -0
  3. package/dest/constants.d.ts.map +1 -0
  4. package/dest/constants.js +2 -0
  5. package/dest/index.d.ts +1 -1
  6. package/dest/index.d.ts.map +1 -1
  7. package/dest/index.js +85 -52
  8. package/dest/oracle/interfaces.d.ts +14 -10
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +10 -12
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +24 -15
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +205 -88
  16. package/dest/rpc_translator.d.ts +35 -20
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +151 -65
  19. package/dest/state_machine/archiver.d.ts +21 -51
  20. package/dest/state_machine/archiver.d.ts.map +1 -1
  21. package/dest/state_machine/archiver.js +63 -94
  22. package/dest/state_machine/dummy_p2p_client.d.ts +21 -14
  23. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  24. package/dest/state_machine/dummy_p2p_client.js +42 -22
  25. package/dest/state_machine/global_variable_builder.d.ts +6 -4
  26. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  27. package/dest/state_machine/global_variable_builder.js +13 -1
  28. package/dest/state_machine/index.d.ts +7 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +40 -23
  31. package/dest/state_machine/mock_epoch_cache.d.ts +14 -10
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +21 -13
  34. package/dest/state_machine/synchronizer.d.ts +3 -2
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +5 -4
  37. package/dest/txe_session.d.ts +26 -15
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +161 -53
  40. package/dest/util/encoding.d.ts +615 -16
  41. package/dest/util/encoding.d.ts.map +1 -1
  42. package/dest/util/encoding.js +1 -1
  43. package/dest/util/expected_failure_error.d.ts +1 -1
  44. package/dest/util/expected_failure_error.d.ts.map +1 -1
  45. package/dest/util/txe_account_store.d.ts +10 -0
  46. package/dest/util/txe_account_store.d.ts.map +1 -0
  47. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  48. package/dest/util/txe_public_contract_data_source.d.ts +8 -8
  49. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  50. package/dest/util/txe_public_contract_data_source.js +12 -29
  51. package/dest/utils/block_creation.d.ts +21 -6
  52. package/dest/utils/block_creation.d.ts.map +1 -1
  53. package/dest/utils/block_creation.js +38 -4
  54. package/dest/utils/tx_effect_creation.d.ts +3 -3
  55. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  56. package/dest/utils/tx_effect_creation.js +4 -7
  57. package/package.json +18 -17
  58. package/src/constants.ts +3 -0
  59. package/src/index.ts +97 -60
  60. package/src/oracle/interfaces.ts +16 -8
  61. package/src/oracle/txe_oracle_public_context.ts +12 -19
  62. package/src/oracle/txe_oracle_top_level_context.ts +249 -127
  63. package/src/rpc_translator.ts +179 -68
  64. package/src/state_machine/archiver.ts +63 -117
  65. package/src/state_machine/dummy_p2p_client.ts +59 -29
  66. package/src/state_machine/global_variable_builder.ts +22 -4
  67. package/src/state_machine/index.ts +60 -21
  68. package/src/state_machine/mock_epoch_cache.ts +25 -20
  69. package/src/state_machine/synchronizer.ts +6 -5
  70. package/src/txe_session.ts +222 -101
  71. package/src/util/encoding.ts +1 -1
  72. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  73. package/src/util/txe_public_contract_data_source.ts +20 -45
  74. package/src/utils/block_creation.ts +49 -14
  75. package/src/utils/tx_effect_creation.ts +5 -12
  76. package/dest/util/txe_account_data_provider.d.ts +0 -10
  77. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  78. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  79. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  80. package/dest/util/txe_contract_data_provider.js +0 -22
  81. 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,18 +46,18 @@ 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';
56
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
48
57
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
49
- import { Body, L2Block } from '@aztec/stdlib/block';
50
58
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
51
59
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
52
- import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
60
+ import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
53
61
  import {
54
62
  PartialPrivateTailPublicInputsForPublic,
55
63
  PrivateKernelTailCircuitPublicInputs,
@@ -57,7 +65,7 @@ import {
57
65
  PublicCallRequest,
58
66
  } from '@aztec/stdlib/kernel';
59
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
60
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
68
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
61
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
62
70
  import {
63
71
  CallContext,
@@ -74,15 +82,11 @@ import {
74
82
  import type { UInt64 } from '@aztec/stdlib/types';
75
83
  import { ForkCheckpoint } from '@aztec/world-state';
76
84
 
85
+ import { DEFAULT_ADDRESS } from '../constants.js';
77
86
  import type { TXEStateMachine } from '../state_machine/index.js';
78
- import type { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
79
- import type { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
87
+ import type { TXEAccountStore } from '../util/txe_account_store.js';
80
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
81
- import {
82
- getSingleTxBlockRequestHash,
83
- insertTxEffectIntoWorldTrees,
84
- makeTXEBlockHeader,
85
- } from '../utils/block_creation.js';
89
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
86
90
  import type { ITxeExecutionOracle } from './interfaces.js';
87
91
 
88
92
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -93,11 +97,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
93
97
 
94
98
  constructor(
95
99
  private stateMachine: TXEStateMachine,
96
- private contractDataProvider: TXEContractDataProvider,
100
+ private contractStore: ContractStore,
101
+ private noteStore: NoteStore,
97
102
  private keyStore: KeyStore,
98
- private addressDataProvider: AddressDataProvider,
99
- private accountDataProvider: TXEAccountDataProvider,
100
- 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,
101
110
  private nextBlockTimestamp: bigint,
102
111
  private version: Fr,
103
112
  private chainId: Fr,
@@ -122,17 +131,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
122
131
  }
123
132
 
124
133
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
125
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
134
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
126
135
  if (!LogLevels[level]) {
127
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
128
137
  }
129
138
  const levelName = LogLevels[level];
130
139
 
131
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;
132
146
  }
133
147
 
134
- async txeGetNextBlockNumber(): Promise<number> {
135
- return (await this.getLastBlockNumber()) + 1;
148
+ async txeGetNextBlockNumber(): Promise<BlockNumber> {
149
+ return BlockNumber((await this.getLastBlockNumber()) + 1);
136
150
  }
137
151
 
138
152
  txeGetNextBlockTimestamp(): Promise<bigint> {
@@ -144,7 +158,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
144
158
  }
145
159
 
146
160
  async txeGetLastTxEffects() {
147
- 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);
148
163
 
149
164
  if (block!.body.txEffects.length != 1) {
150
165
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -156,6 +171,36 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
171
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
157
172
  }
158
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
+
159
204
  async txeAdvanceBlocksBy(blocks: number) {
160
205
  this.logger.debug(`time traveling ${blocks} blocks`);
161
206
 
@@ -183,8 +228,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
183
228
  if (!secret.equals(Fr.ZERO)) {
184
229
  await this.txeAddAccount(artifact, instance, secret);
185
230
  } else {
186
- await this.contractDataProvider.addContractInstance(instance);
187
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
231
+ await this.contractStore.addContractInstance(instance);
232
+ await this.contractStore.addContractArtifact(artifact);
188
233
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
189
234
  }
190
235
  }
@@ -193,29 +238,29 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
193
238
  const partialAddress = await computePartialAddress(instance);
194
239
 
195
240
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
196
- await this.contractDataProvider.addContractInstance(instance);
197
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
241
+ await this.contractStore.addContractInstance(instance);
242
+ await this.contractStore.addContractArtifact(artifact);
198
243
 
199
244
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
200
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
201
- await this.addressDataProvider.addCompleteAddress(completeAddress);
245
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
246
+ await this.addressStore.addCompleteAddress(completeAddress);
202
247
  this.logger.debug(`Created account ${completeAddress.address}`);
203
248
 
204
249
  return completeAddress;
205
250
  }
206
251
 
207
252
  async txeCreateAccount(secret: Fr) {
208
- // This is a footgun !
253
+ // This is a foot gun !
209
254
  const completeAddress = await this.keyStore.addAccount(secret, secret);
210
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
211
- await this.addressDataProvider.addCompleteAddress(completeAddress);
255
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
256
+ await this.addressStore.addCompleteAddress(completeAddress);
212
257
  this.logger.debug(`Created account ${completeAddress.address}`);
213
258
 
214
259
  return completeAddress;
215
260
  }
216
261
 
217
262
  async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
218
- const account = await this.accountDataProvider.getAccount(address);
263
+ const account = await this.accountStore.getAccount(address);
219
264
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
220
265
 
221
266
  const schnorr = new Schnorr();
@@ -236,19 +281,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
236
281
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
237
282
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
238
283
 
239
- const block = new L2Block(
240
- makeAppendOnlyTreeSnapshot(),
241
- await makeTXEBlockHeader(
242
- forkedWorldTrees,
243
- makeGlobalVariables(undefined, {
244
- blockNumber,
245
- timestamp: this.nextBlockTimestamp,
246
- version: this.version,
247
- chainId: this.chainId,
248
- }),
249
- ),
250
- new Body([txEffect]),
251
- );
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]);
252
291
 
253
292
  await forkedWorldTrees.close();
254
293
 
@@ -264,12 +303,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
264
303
  args: Fr[],
265
304
  argsHash: Fr = Fr.zero(),
266
305
  isStaticCall: boolean = false,
306
+ jobId: string,
267
307
  ) {
268
308
  this.logger.verbose(
269
- `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}`,
270
310
  );
271
311
 
272
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
312
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
273
313
  if (!artifact) {
274
314
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
275
315
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -277,51 +317,77 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
277
317
  throw new Error(message);
278
318
  }
279
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
+
280
339
  const blockNumber = await this.txeGetNextBlockNumber();
281
340
 
282
341
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
283
342
 
284
343
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
285
-
286
344
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
287
-
288
345
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
289
346
 
290
347
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
291
348
 
292
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
293
-
294
- const txRequestHash = getSingleTxBlockRequestHash(blockNumber);
295
- const noteCache = new ExecutionNoteCache(txRequestHash);
349
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
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);
296
356
  const taggingIndexCache = new ExecutionTaggingIndexCache();
297
357
 
298
358
  const simulator = new WASMSimulator();
299
359
 
300
- const privateExecutionOracle = new PrivateExecutionOracle(
360
+ const privateExecutionOracle = new PrivateExecutionOracle({
301
361
  argsHash,
302
362
  txContext,
303
363
  callContext,
304
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
305
- blockHeader,
306
- /** List of transient auth witnesses to be used during this simulation */
307
- Array.from(this.authwits.values()),
308
- /** List of transient auth witnesses to be used during this simulation */
309
- [],
310
- 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)]),
311
369
  noteCache,
312
370
  taggingIndexCache,
313
- this.pxeOracleInterface,
314
- 0,
315
- 1,
316
- undefined, // log
317
- undefined, // scopes
318
- /**
319
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
320
- * contract would perform, including setting senderForTags.
321
- */
322
- 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,
323
389
  simulator,
324
- );
390
+ });
325
391
 
326
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.
327
393
  let result: PrivateExecutionResult;
@@ -348,19 +414,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
348
414
  }),
349
415
  );
350
416
 
351
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
352
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
353
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
354
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
417
+ noteCache.finish();
418
+ const nonceGenerator = noteCache.getNonceGenerator();
419
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
355
420
  } catch (err) {
356
421
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
357
422
  }
358
423
 
359
- // According to the protocol rules, the nonce generator for the note hashes
360
- // can either be the first nullifier in the tx or the hash of the initial tx request
361
- // if there are none.
362
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? txRequestHash : result.firstNullifier;
363
- 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
+ );
364
433
 
365
434
  const globals = makeGlobalVariables();
366
435
  globals.blockNumber = blockNumber;
@@ -371,17 +440,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
371
440
 
372
441
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
373
442
 
374
- 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
+ );
375
448
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
449
+ const config = PublicSimulatorConfig.from({
450
+ skipFeeEnforcement: true,
451
+ collectDebugLogs: true,
452
+ collectHints: false,
453
+ collectStatistics: false,
454
+ collectCallMetadata: true,
455
+ });
376
456
  const processor = new PublicProcessor(
377
457
  globals,
378
458
  guardedMerkleTrees,
379
459
  contractsDB,
380
- new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
381
- doMerkleOperations: true,
382
- skipFeeEnforcement: true,
383
- }),
460
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
384
461
  new TestDateProvider(),
462
+ undefined,
463
+ createLogger('simulator:public-processor', bindings),
385
464
  );
386
465
 
387
466
  const tx = await Tx.create({
@@ -406,7 +485,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
406
485
  } else if (!processedTx.revertCode.isOK()) {
407
486
  if (processedTx.revertReason) {
408
487
  try {
409
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
488
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
410
489
  // eslint-disable-next-line no-empty
411
490
  } catch {}
412
491
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -435,13 +514,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
435
514
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
436
515
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
437
516
 
438
- const body = new Body([txEffect]);
439
-
440
- const l2Block = new L2Block(
441
- makeAppendOnlyTreeSnapshot(),
442
- await makeTXEBlockHeader(forkedWorldTrees, globals),
443
- body,
444
- );
517
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
445
518
 
446
519
  await this.stateMachine.handleL2Block(l2Block);
447
520
 
@@ -457,7 +530,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
457
530
  isStaticCall: boolean,
458
531
  ) {
459
532
  this.logger.verbose(
460
- `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}`,
461
534
  );
462
535
 
463
536
  const blockNumber = await this.txeGetNextBlockNumber();
@@ -470,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
470
543
 
471
544
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
472
545
 
473
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
546
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
547
 
475
548
  const calldataHash = await computeCalldataHash(calldata);
476
549
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -484,22 +557,36 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
484
557
 
485
558
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
486
559
 
487
- 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
+ );
488
565
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
489
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
490
- doMerkleOperations: true,
566
+ const config = PublicSimulatorConfig.from({
491
567
  skipFeeEnforcement: true,
568
+ collectDebugLogs: true,
569
+ collectHints: false,
570
+ collectStatistics: false,
571
+ collectCallMetadata: true,
492
572
  });
493
- 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
+ );
494
583
 
495
584
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
496
585
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
497
586
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
498
587
  // unique.
499
588
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
500
- if (!isStaticCall) {
501
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
502
- }
589
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
503
590
 
504
591
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
505
592
  // may require producing reverts.
@@ -523,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
523
610
  constantData,
524
611
  /*gasUsed=*/ new Gas(0, 0),
525
612
  /*feePayer=*/ AztecAddress.zero(),
526
- /*includeByTimestamp=*/ 0n,
613
+ /*expirationTimestamp=*/ 0n,
527
614
  inputsForPublic,
528
615
  undefined,
529
616
  );
@@ -550,7 +637,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
550
637
  } else if (!processedTx.revertCode.isOK()) {
551
638
  if (processedTx.revertReason) {
552
639
  try {
553
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
640
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
554
641
  // eslint-disable-next-line no-empty
555
642
  } catch {}
556
643
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -582,13 +669,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
582
669
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
583
670
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
584
671
 
585
- const body = new Body([txEffect]);
586
-
587
- const l2Block = new L2Block(
588
- makeAppendOnlyTreeSnapshot(),
589
- await makeTXEBlockHeader(forkedWorldTrees, globals),
590
- body,
591
- );
672
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
592
673
 
593
674
  await this.stateMachine.handleL2Block(l2Block);
594
675
 
@@ -597,23 +678,46 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
597
678
  return returnValues ?? [];
598
679
  }
599
680
 
600
- async txeSimulateUtilityFunction(
681
+ async txeExecuteUtilityFunction(
601
682
  targetContractAddress: AztecAddress,
602
683
  functionSelector: FunctionSelector,
603
684
  args: Fr[],
685
+ jobId: string,
604
686
  ) {
605
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
687
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
606
688
  if (!artifact) {
607
689
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
608
690
  }
609
691
 
610
- 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({
611
706
  name: artifact.name,
612
- selector: functionSelector,
613
707
  to: targetContractAddress,
614
- };
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
+ }
615
718
 
616
- 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);
617
721
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
618
722
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
619
723
  }
@@ -624,9 +728,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
624
728
  });
625
729
 
626
730
  try {
627
- 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
+ });
628
749
  const acirExecutionResult = await new WASMSimulator()
629
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
750
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
630
751
  .catch((err: Error) => {
631
752
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
632
753
  throw new ExecutionError(
@@ -640,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
640
761
  );
641
762
  });
642
763
 
643
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
764
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
644
765
  return witnessMapToFields(acirExecutionResult.returnWitness);
645
766
  } catch (err) {
646
- 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'));
647
768
  }
648
769
  }
649
770
 
@@ -652,7 +773,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
652
773
  return [this.nextBlockTimestamp, this.authwits];
653
774
  }
654
775
 
655
- private async getLastBlockNumber(): Promise<number> {
656
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
776
+ private async getLastBlockNumber(): Promise<BlockNumber> {
777
+ const header = await this.stateMachine.node.getBlockHeader('latest');
778
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
657
779
  }
658
780
  }