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

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 +91 -56
  7. package/dest/oracle/interfaces.d.ts +33 -29
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +16 -16
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +20 -22
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +36 -27
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +206 -98
  15. package/dest/rpc_translator.d.ts +91 -79
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +330 -170
  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 +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 +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 +26 -15
  37. package/dest/txe_session.d.ts.map +1 -1
  38. package/dest/txe_session.js +161 -55
  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 +103 -63
  57. package/src/oracle/interfaces.ts +36 -32
  58. package/src/oracle/txe_oracle_public_context.ts +21 -28
  59. package/src/oracle/txe_oracle_top_level_context.ts +251 -138
  60. package/src/rpc_translator.ts +368 -174
  61. package/src/state_machine/archiver.ts +59 -114
  62. package/src/state_machine/dummy_p2p_client.ts +58 -33
  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 +222 -103
  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,16 @@ 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,
102
110
  private nextBlockTimestamp: bigint,
103
111
  private version: Fr,
104
112
  private chainId: Fr,
@@ -108,7 +116,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
108
116
  this.logger.debug('Entering Top Level Context');
109
117
  }
110
118
 
111
- utilityAssertCompatibleOracleVersion(version: number): void {
119
+ assertCompatibleOracleVersion(version: number): void {
112
120
  if (version !== ORACLE_VERSION) {
113
121
  throw new Error(
114
122
  `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
@@ -118,34 +126,40 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
118
126
 
119
127
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
120
128
  // setup.
121
- utilityGetRandomField(): Fr {
129
+ getRandomField(): Fr {
122
130
  return Fr.random();
123
131
  }
124
132
 
125
133
  // 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 {
134
+ log(level: number, message: string, fields: Fr[]): Promise<void> {
127
135
  if (!LogLevels[level]) {
128
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
129
137
  }
130
138
  const levelName = LogLevels[level];
131
139
 
132
140
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
141
+ return Promise.resolve();
142
+ }
143
+
144
+ getDefaultAddress(): AztecAddress {
145
+ return DEFAULT_ADDRESS;
133
146
  }
134
147
 
135
- async txeGetNextBlockNumber(): Promise<number> {
136
- return (await this.getLastBlockNumber()) + 1;
148
+ async getNextBlockNumber(): Promise<BlockNumber> {
149
+ return BlockNumber((await this.getLastBlockNumber()) + 1);
137
150
  }
138
151
 
139
- txeGetNextBlockTimestamp(): Promise<bigint> {
152
+ getNextBlockTimestamp(): Promise<bigint> {
140
153
  return Promise.resolve(this.nextBlockTimestamp);
141
154
  }
142
155
 
143
- async txeGetLastBlockTimestamp() {
156
+ async getLastBlockTimestamp() {
144
157
  return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
145
158
  }
146
159
 
147
- async txeGetLastTxEffects() {
148
- const block = await this.stateMachine.archiver.getBlock('latest');
160
+ async getLastTxEffects() {
161
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
162
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
149
163
 
150
164
  if (block!.body.txEffects.length != 1) {
151
165
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -157,7 +171,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
157
171
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
158
172
  }
159
173
 
160
- async txeAdvanceBlocksBy(blocks: number) {
174
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
175
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
176
+ this.logger.debug(`Skipping sync in getPrivateEvents 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 getPrivateEvents(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
+
204
+ async advanceBlocksBy(blocks: number) {
161
205
  this.logger.debug(`time traveling ${blocks} blocks`);
162
206
 
163
207
  for (let i = 0; i < blocks; i++) {
@@ -165,12 +209,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
165
209
  }
166
210
  }
167
211
 
168
- txeAdvanceTimestampBy(duration: UInt64) {
212
+ advanceTimestampBy(duration: UInt64) {
169
213
  this.logger.debug(`time traveling ${duration} seconds`);
170
214
  this.nextBlockTimestamp += duration;
171
215
  }
172
216
 
173
- async txeDeploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
217
+ async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
174
218
  // Emit deployment nullifier
175
219
  await this.mineBlock({
176
220
  nullifiers: [
@@ -182,41 +226,41 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
182
226
  });
183
227
 
184
228
  if (!secret.equals(Fr.ZERO)) {
185
- await this.txeAddAccount(artifact, instance, secret);
229
+ await this.addAccount(artifact, instance, secret);
186
230
  } else {
187
- await this.contractDataProvider.addContractInstance(instance);
188
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
231
+ await this.contractStore.addContractInstance(instance);
232
+ await this.contractStore.addContractArtifact(artifact);
189
233
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
190
234
  }
191
235
  }
192
236
 
193
- async txeAddAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
237
+ async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
194
238
  const partialAddress = await computePartialAddress(instance);
195
239
 
196
240
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
197
- await this.contractDataProvider.addContractInstance(instance);
198
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
241
+ await this.contractStore.addContractInstance(instance);
242
+ await this.contractStore.addContractArtifact(artifact);
199
243
 
200
244
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
201
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
202
- await this.addressDataProvider.addCompleteAddress(completeAddress);
245
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
246
+ await this.addressStore.addCompleteAddress(completeAddress);
203
247
  this.logger.debug(`Created account ${completeAddress.address}`);
204
248
 
205
249
  return completeAddress;
206
250
  }
207
251
 
208
- async txeCreateAccount(secret: Fr) {
209
- // This is a footgun !
252
+ async createAccount(secret: Fr) {
253
+ // This is a foot gun !
210
254
  const completeAddress = await this.keyStore.addAccount(secret, secret);
211
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
212
- await this.addressDataProvider.addCompleteAddress(completeAddress);
255
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
256
+ await this.addressStore.addCompleteAddress(completeAddress);
213
257
  this.logger.debug(`Created account ${completeAddress.address}`);
214
258
 
215
259
  return completeAddress;
216
260
  }
217
261
 
218
- async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
219
- const account = await this.accountDataProvider.getAccount(address);
262
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
263
+ const account = await this.accountStore.getAccount(address);
220
264
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
221
265
 
222
266
  const schnorr = new Schnorr();
@@ -228,7 +272,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
228
272
  }
229
273
 
230
274
  async mineBlock(options: { nullifiers?: Fr[] } = {}) {
231
- const blockNumber = await this.txeGetNextBlockNumber();
275
+ const blockNumber = await this.getNextBlockNumber();
232
276
 
233
277
  const txEffect = TxEffect.empty();
234
278
  txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
@@ -237,19 +281,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
237
281
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
238
282
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
239
283
 
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
- );
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]);
253
291
 
254
292
  await forkedWorldTrees.close();
255
293
 
@@ -258,19 +296,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
258
296
  await this.stateMachine.handleL2Block(block);
259
297
  }
260
298
 
261
- async txePrivateCallNewFlow(
299
+ async privateCallNewFlow(
262
300
  from: AztecAddress,
263
301
  targetContractAddress: AztecAddress = AztecAddress.zero(),
264
302
  functionSelector: FunctionSelector = FunctionSelector.empty(),
265
303
  args: Fr[],
266
304
  argsHash: Fr = Fr.zero(),
267
305
  isStaticCall: boolean = false,
306
+ jobId: string,
268
307
  ) {
269
308
  this.logger.verbose(
270
- `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}`,
271
310
  );
272
311
 
273
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
312
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
274
313
  if (!artifact) {
275
314
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
276
315
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -278,51 +317,77 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
278
317
  throw new Error(message);
279
318
  }
280
319
 
281
- const blockNumber = await this.txeGetNextBlockNumber();
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
+
339
+ const blockNumber = await this.getNextBlockNumber();
282
340
 
283
341
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
284
342
 
285
343
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
286
-
287
344
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
288
-
289
345
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
290
346
 
291
347
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
292
348
 
293
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
294
-
295
349
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
296
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);
297
356
  const taggingIndexCache = new ExecutionTaggingIndexCache();
298
357
 
299
358
  const simulator = new WASMSimulator();
300
359
 
301
- const privateExecutionOracle = new PrivateExecutionOracle(
360
+ const privateExecutionOracle = new PrivateExecutionOracle({
302
361
  argsHash,
303
362
  txContext,
304
363
  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)]),
364
+ anchorBlockHeader: blockHeader,
365
+ utilityExecutor,
366
+ authWitnesses: Array.from(this.authwits.values()),
367
+ capsules: [],
368
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
312
369
  noteCache,
313
370
  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,
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,
324
389
  simulator,
325
- );
390
+ });
326
391
 
327
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.
328
393
  let result: PrivateExecutionResult;
@@ -344,24 +409,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
344
409
  );
345
410
  const publicFunctionsCalldata = await Promise.all(
346
411
  publicCallRequests.map(async r => {
347
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
412
+ const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
348
413
  return new HashedValues(calldata, r.calldataHash);
349
414
  }),
350
415
  );
351
416
 
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);
417
+ noteCache.finish();
418
+ const nonceGenerator = noteCache.getNonceGenerator();
419
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
356
420
  } catch (err) {
357
421
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
358
422
  }
359
423
 
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);
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
+ );
365
433
 
366
434
  const globals = makeGlobalVariables();
367
435
  globals.blockNumber = blockNumber;
@@ -372,7 +440,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
372
440
 
373
441
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
374
442
 
375
- 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
+ );
376
448
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
377
449
  const config = PublicSimulatorConfig.from({
378
450
  skipFeeEnforcement: true,
@@ -385,8 +457,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
385
457
  globals,
386
458
  guardedMerkleTrees,
387
459
  contractsDB,
388
- new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
460
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
389
461
  new TestDateProvider(),
462
+ undefined,
463
+ createLogger('simulator:public-processor', bindings),
390
464
  );
391
465
 
392
466
  const tx = await Tx.create({
@@ -411,7 +485,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
411
485
  } else if (!processedTx.revertCode.isOK()) {
412
486
  if (processedTx.revertReason) {
413
487
  try {
414
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
488
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
415
489
  // eslint-disable-next-line no-empty
416
490
  } catch {}
417
491
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -440,13 +514,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
440
514
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
441
515
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
442
516
 
443
- const body = new Body([txEffect]);
444
-
445
- const l2Block = new L2Block(
446
- makeAppendOnlyTreeSnapshot(),
447
- await makeTXEBlockHeader(forkedWorldTrees, globals),
448
- body,
449
- );
517
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
450
518
 
451
519
  await this.stateMachine.handleL2Block(l2Block);
452
520
 
@@ -455,17 +523,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
455
523
  return executionResult.returnValues ?? [];
456
524
  }
457
525
 
458
- async txePublicCallNewFlow(
526
+ async publicCallNewFlow(
459
527
  from: AztecAddress,
460
528
  targetContractAddress: AztecAddress,
461
529
  calldata: Fr[],
462
530
  isStaticCall: boolean,
463
531
  ) {
464
532
  this.logger.verbose(
465
- `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}`,
466
534
  );
467
535
 
468
- const blockNumber = await this.txeGetNextBlockNumber();
536
+ const blockNumber = await this.getNextBlockNumber();
469
537
 
470
538
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
471
539
 
@@ -475,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
475
543
 
476
544
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
477
545
 
478
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
546
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
479
547
 
480
548
  const calldataHash = await computeCalldataHash(calldata);
481
549
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -489,7 +557,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
489
557
 
490
558
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
491
559
 
492
- 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
+ );
493
565
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
494
566
  const config = PublicSimulatorConfig.from({
495
567
  skipFeeEnforcement: true,
@@ -498,17 +570,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
498
570
  collectStatistics: false,
499
571
  collectCallMetadata: true,
500
572
  });
501
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
502
- 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
+ );
503
583
 
504
584
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
505
585
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
506
586
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
507
587
  // unique.
508
588
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
509
- if (!isStaticCall) {
510
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
511
- }
589
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
512
590
 
513
591
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
514
592
  // may require producing reverts.
@@ -532,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
532
610
  constantData,
533
611
  /*gasUsed=*/ new Gas(0, 0),
534
612
  /*feePayer=*/ AztecAddress.zero(),
535
- /*includeByTimestamp=*/ 0n,
613
+ /*expirationTimestamp=*/ 0n,
536
614
  inputsForPublic,
537
615
  undefined,
538
616
  );
@@ -559,7 +637,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
559
637
  } else if (!processedTx.revertCode.isOK()) {
560
638
  if (processedTx.revertReason) {
561
639
  try {
562
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
640
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
563
641
  // eslint-disable-next-line no-empty
564
642
  } catch {}
565
643
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -591,13 +669,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
591
669
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
592
670
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
593
671
 
594
- const body = new Body([txEffect]);
595
-
596
- const l2Block = new L2Block(
597
- makeAppendOnlyTreeSnapshot(),
598
- await makeTXEBlockHeader(forkedWorldTrees, globals),
599
- body,
600
- );
672
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
601
673
 
602
674
  await this.stateMachine.handleL2Block(l2Block);
603
675
 
@@ -606,23 +678,46 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
606
678
  return returnValues ?? [];
607
679
  }
608
680
 
609
- async txeSimulateUtilityFunction(
681
+ async executeUtilityFunction(
610
682
  targetContractAddress: AztecAddress,
611
683
  functionSelector: FunctionSelector,
612
684
  args: Fr[],
685
+ jobId: string,
613
686
  ) {
614
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
687
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
615
688
  if (!artifact) {
616
689
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
617
690
  }
618
691
 
619
- 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({
620
706
  name: artifact.name,
621
- selector: functionSelector,
622
707
  to: targetContractAddress,
623
- };
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
+ }
624
718
 
625
- 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);
626
721
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
627
722
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
628
723
  }
@@ -633,9 +728,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
633
728
  });
634
729
 
635
730
  try {
636
- 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
+ });
637
749
  const acirExecutionResult = await new WASMSimulator()
638
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
750
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
639
751
  .catch((err: Error) => {
640
752
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
641
753
  throw new ExecutionError(
@@ -649,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
649
761
  );
650
762
  });
651
763
 
652
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
764
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
653
765
  return witnessMapToFields(acirExecutionResult.returnWitness);
654
766
  } catch (err) {
655
- 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'));
656
768
  }
657
769
  }
658
770
 
@@ -661,7 +773,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
661
773
  return [this.nextBlockTimestamp, this.authwits];
662
774
  }
663
775
 
664
- private async getLastBlockNumber(): Promise<number> {
665
- 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;
666
779
  }
667
780
  }