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

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 +91 -56
  8. package/dest/oracle/interfaces.d.ts +33 -29
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +16 -16
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +20 -22
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +37 -27
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +228 -106
  16. package/dest/rpc_translator.d.ts +98 -78
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +367 -171
  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 +66 -99
  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 +9 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +44 -23
  31. package/dest/state_machine/mock_epoch_cache.d.ts +30 -12
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +53 -15
  34. package/dest/state_machine/synchronizer.d.ts +6 -5
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +8 -7
  37. package/dest/txe_session.d.ts +27 -15
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +173 -56
  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 +103 -63
  60. package/src/oracle/interfaces.ts +36 -32
  61. package/src/oracle/txe_oracle_public_context.ts +21 -28
  62. package/src/oracle/txe_oracle_top_level_context.ts +272 -145
  63. package/src/rpc_translator.ts +422 -194
  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 +64 -21
  68. package/src/state_machine/mock_epoch_cache.ts +67 -23
  69. package/src/state_machine/synchronizer.ts +9 -8
  70. package/src/txe_session.ts +239 -105
  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,24 @@ 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
+ type ContractSyncService,
21
+ NoteStore,
16
22
  ORACLE_VERSION,
17
- PXEOracleInterface,
23
+ PrivateEventStore,
24
+ RecipientTaggingStore,
25
+ SenderAddressBookStore,
26
+ SenderTaggingStore,
18
27
  enrichPublicSimulationError,
19
28
  } from '@aztec/pxe/server';
20
29
  import {
@@ -38,18 +47,18 @@ import {
38
47
  witnessMapToFields,
39
48
  } from '@aztec/simulator/client';
40
49
  import {
50
+ CppPublicTxSimulator,
41
51
  GuardedMerkleTreeOperations,
42
52
  PublicContractsDB,
43
53
  PublicProcessor,
44
- PublicTxSimulator,
45
54
  } from '@aztec/simulator/server';
46
- import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
55
+ import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
47
56
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
57
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
48
58
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
49
- import { Body, L2Block } from '@aztec/stdlib/block';
50
59
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
51
60
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
52
- import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
61
+ import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
53
62
  import {
54
63
  PartialPrivateTailPublicInputsForPublic,
55
64
  PrivateKernelTailCircuitPublicInputs,
@@ -57,7 +66,7 @@ import {
57
66
  PublicCallRequest,
58
67
  } from '@aztec/stdlib/kernel';
59
68
  import { ChonkProof } from '@aztec/stdlib/proofs';
60
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
69
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
61
70
  import { MerkleTreeId } from '@aztec/stdlib/trees';
62
71
  import {
63
72
  CallContext,
@@ -74,15 +83,11 @@ import {
74
83
  import type { UInt64 } from '@aztec/stdlib/types';
75
84
  import { ForkCheckpoint } from '@aztec/world-state';
76
85
 
86
+ import { DEFAULT_ADDRESS } from '../constants.js';
77
87
  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';
88
+ import type { TXEAccountStore } from '../util/txe_account_store.js';
80
89
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
81
- import {
82
- getSingleTxBlockRequestHash,
83
- insertTxEffectIntoWorldTrees,
84
- makeTXEBlockHeader,
85
- } from '../utils/block_creation.js';
90
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
86
91
  import type { ITxeExecutionOracle } from './interfaces.js';
87
92
 
88
93
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -93,21 +98,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
93
98
 
94
99
  constructor(
95
100
  private stateMachine: TXEStateMachine,
96
- private contractDataProvider: TXEContractDataProvider,
101
+ private contractStore: ContractStore,
102
+ private noteStore: NoteStore,
97
103
  private keyStore: KeyStore,
98
- private addressDataProvider: AddressDataProvider,
99
- private accountDataProvider: TXEAccountDataProvider,
100
- private pxeOracleInterface: PXEOracleInterface,
104
+ private addressStore: AddressStore,
105
+ private accountStore: TXEAccountStore,
106
+ private senderTaggingStore: SenderTaggingStore,
107
+ private recipientTaggingStore: RecipientTaggingStore,
108
+ private senderAddressBookStore: SenderAddressBookStore,
109
+ private capsuleStore: CapsuleStore,
110
+ private privateEventStore: PrivateEventStore,
101
111
  private nextBlockTimestamp: bigint,
102
112
  private version: Fr,
103
113
  private chainId: Fr,
104
114
  private authwits: Map<string, AuthWitness>,
115
+ private readonly contractSyncService: ContractSyncService,
105
116
  ) {
106
117
  this.logger = createLogger('txe:top_level_context');
107
118
  this.logger.debug('Entering Top Level Context');
108
119
  }
109
120
 
110
- utilityAssertCompatibleOracleVersion(version: number): void {
121
+ assertCompatibleOracleVersion(version: number): void {
111
122
  if (version !== ORACLE_VERSION) {
112
123
  throw new Error(
113
124
  `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
@@ -117,34 +128,40 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
117
128
 
118
129
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
119
130
  // setup.
120
- utilityGetRandomField(): Fr {
131
+ getRandomField(): Fr {
121
132
  return Fr.random();
122
133
  }
123
134
 
124
135
  // 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 {
136
+ log(level: number, message: string, fields: Fr[]): Promise<void> {
126
137
  if (!LogLevels[level]) {
127
- throw new Error(`Invalid debug log level: ${level}`);
138
+ throw new Error(`Invalid log level: ${level}`);
128
139
  }
129
140
  const levelName = LogLevels[level];
130
141
 
131
142
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
143
+ return Promise.resolve();
144
+ }
145
+
146
+ getDefaultAddress(): AztecAddress {
147
+ return DEFAULT_ADDRESS;
132
148
  }
133
149
 
134
- async txeGetNextBlockNumber(): Promise<number> {
135
- return (await this.getLastBlockNumber()) + 1;
150
+ async getNextBlockNumber(): Promise<BlockNumber> {
151
+ return BlockNumber((await this.getLastBlockNumber()) + 1);
136
152
  }
137
153
 
138
- txeGetNextBlockTimestamp(): Promise<bigint> {
154
+ getNextBlockTimestamp(): Promise<bigint> {
139
155
  return Promise.resolve(this.nextBlockTimestamp);
140
156
  }
141
157
 
142
- async txeGetLastBlockTimestamp() {
158
+ async getLastBlockTimestamp() {
143
159
  return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
144
160
  }
145
161
 
146
- async txeGetLastTxEffects() {
147
- const block = await this.stateMachine.archiver.getBlock('latest');
162
+ async getLastTxEffects() {
163
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
164
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
148
165
 
149
166
  if (block!.body.txEffects.length != 1) {
150
167
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -156,7 +173,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
173
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
157
174
  }
158
175
 
159
- async txeAdvanceBlocksBy(blocks: number) {
176
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
177
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
178
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
179
+ return;
180
+ }
181
+
182
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
183
+ await this.stateMachine.contractSyncService.ensureContractSynced(
184
+ contractAddress,
185
+ null,
186
+ async (call, execScopes) => {
187
+ await this.executeUtilityCall(call, execScopes, jobId);
188
+ },
189
+ blockHeader,
190
+ jobId,
191
+ [scope],
192
+ );
193
+ }
194
+
195
+ async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
196
+ return (
197
+ await this.privateEventStore.getPrivateEvents(selector, {
198
+ contractAddress,
199
+ scopes: [scope],
200
+ fromBlock: 0,
201
+ toBlock: (await this.getLastBlockNumber()) + 1,
202
+ })
203
+ ).map(e => e.packedEvent);
204
+ }
205
+
206
+ async advanceBlocksBy(blocks: number) {
160
207
  this.logger.debug(`time traveling ${blocks} blocks`);
161
208
 
162
209
  for (let i = 0; i < blocks; i++) {
@@ -164,12 +211,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
164
211
  }
165
212
  }
166
213
 
167
- txeAdvanceTimestampBy(duration: UInt64) {
214
+ advanceTimestampBy(duration: UInt64) {
168
215
  this.logger.debug(`time traveling ${duration} seconds`);
169
216
  this.nextBlockTimestamp += duration;
170
217
  }
171
218
 
172
- async txeDeploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
219
+ async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
173
220
  // Emit deployment nullifier
174
221
  await this.mineBlock({
175
222
  nullifiers: [
@@ -181,41 +228,41 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
181
228
  });
182
229
 
183
230
  if (!secret.equals(Fr.ZERO)) {
184
- await this.txeAddAccount(artifact, instance, secret);
231
+ await this.addAccount(artifact, instance, secret);
185
232
  } else {
186
- await this.contractDataProvider.addContractInstance(instance);
187
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
233
+ await this.contractStore.addContractInstance(instance);
234
+ await this.contractStore.addContractArtifact(artifact);
188
235
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
189
236
  }
190
237
  }
191
238
 
192
- async txeAddAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
239
+ async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
193
240
  const partialAddress = await computePartialAddress(instance);
194
241
 
195
242
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
196
- await this.contractDataProvider.addContractInstance(instance);
197
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
243
+ await this.contractStore.addContractInstance(instance);
244
+ await this.contractStore.addContractArtifact(artifact);
198
245
 
199
246
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
200
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
201
- await this.addressDataProvider.addCompleteAddress(completeAddress);
247
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
248
+ await this.addressStore.addCompleteAddress(completeAddress);
202
249
  this.logger.debug(`Created account ${completeAddress.address}`);
203
250
 
204
251
  return completeAddress;
205
252
  }
206
253
 
207
- async txeCreateAccount(secret: Fr) {
208
- // This is a footgun !
254
+ async createAccount(secret: Fr) {
255
+ // This is a foot gun !
209
256
  const completeAddress = await this.keyStore.addAccount(secret, secret);
210
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
211
- await this.addressDataProvider.addCompleteAddress(completeAddress);
257
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
258
+ await this.addressStore.addCompleteAddress(completeAddress);
212
259
  this.logger.debug(`Created account ${completeAddress.address}`);
213
260
 
214
261
  return completeAddress;
215
262
  }
216
263
 
217
- async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
218
- const account = await this.accountDataProvider.getAccount(address);
264
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
265
+ const account = await this.accountStore.getAccount(address);
219
266
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
220
267
 
221
268
  const schnorr = new Schnorr();
@@ -227,7 +274,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
227
274
  }
228
275
 
229
276
  async mineBlock(options: { nullifiers?: Fr[] } = {}) {
230
- const blockNumber = await this.txeGetNextBlockNumber();
277
+ const blockNumber = await this.getNextBlockNumber();
231
278
 
232
279
  const txEffect = TxEffect.empty();
233
280
  txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
@@ -236,19 +283,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
236
283
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
237
284
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
238
285
 
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
- );
286
+ const globals = makeGlobalVariables(undefined, {
287
+ blockNumber,
288
+ timestamp: this.nextBlockTimestamp,
289
+ version: this.version,
290
+ chainId: this.chainId,
291
+ });
292
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
252
293
 
253
294
  await forkedWorldTrees.close();
254
295
 
@@ -257,19 +298,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
257
298
  await this.stateMachine.handleL2Block(block);
258
299
  }
259
300
 
260
- async txePrivateCallNewFlow(
301
+ async privateCallNewFlow(
261
302
  from: AztecAddress,
262
303
  targetContractAddress: AztecAddress = AztecAddress.zero(),
263
304
  functionSelector: FunctionSelector = FunctionSelector.empty(),
264
305
  args: Fr[],
265
306
  argsHash: Fr = Fr.zero(),
266
307
  isStaticCall: boolean = false,
308
+ jobId: string,
267
309
  ) {
268
310
  this.logger.verbose(
269
- `Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
311
+ `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
270
312
  );
271
313
 
272
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
314
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
273
315
  if (!artifact) {
274
316
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
275
317
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -277,51 +319,78 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
277
319
  throw new Error(message);
278
320
  }
279
321
 
280
- const blockNumber = await this.txeGetNextBlockNumber();
322
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
323
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
324
+ const effectiveScopes = from.isZero() ? [] : [from];
325
+
326
+ // Sync notes before executing private function to discover notes from previous transactions
327
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
328
+ await this.executeUtilityCall(call, execScopes, jobId);
329
+ };
330
+
331
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
332
+ await this.stateMachine.contractSyncService.ensureContractSynced(
333
+ targetContractAddress,
334
+ functionSelector,
335
+ utilityExecutor,
336
+ blockHeader,
337
+ jobId,
338
+ effectiveScopes,
339
+ );
340
+
341
+ const blockNumber = await this.getNextBlockNumber();
281
342
 
282
343
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
283
344
 
284
345
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
285
-
286
346
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
287
-
288
347
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
289
348
 
290
349
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
291
350
 
292
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
293
-
294
- const txRequestHash = getSingleTxBlockRequestHash(blockNumber);
295
- const noteCache = new ExecutionNoteCache(txRequestHash);
351
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
352
+ const noteCache = new ExecutionNoteCache(protocolNullifier);
353
+ // In production, the account contract sets the min revertible counter before calling the app function.
354
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
355
+ // marking all side effects as revertible.
356
+ const minRevertibleSideEffectCounter = 1;
357
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
296
358
  const taggingIndexCache = new ExecutionTaggingIndexCache();
297
359
 
298
360
  const simulator = new WASMSimulator();
299
361
 
300
- const privateExecutionOracle = new PrivateExecutionOracle(
362
+ const privateExecutionOracle = new PrivateExecutionOracle({
301
363
  argsHash,
302
364
  txContext,
303
365
  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)]),
366
+ anchorBlockHeader: blockHeader,
367
+ utilityExecutor,
368
+ authWitnesses: Array.from(this.authwits.values()),
369
+ capsules: [],
370
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
311
371
  noteCache,
312
372
  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,
373
+ contractStore: this.contractStore,
374
+ noteStore: this.noteStore,
375
+ keyStore: this.keyStore,
376
+ addressStore: this.addressStore,
377
+ aztecNode: this.stateMachine.node,
378
+ senderTaggingStore: this.senderTaggingStore,
379
+ recipientTaggingStore: this.recipientTaggingStore,
380
+ senderAddressBookStore: this.senderAddressBookStore,
381
+ capsuleStore: this.capsuleStore,
382
+ privateEventStore: this.privateEventStore,
383
+ contractSyncService: this.stateMachine.contractSyncService,
384
+ jobId,
385
+ totalPublicCalldataCount: 0,
386
+ sideEffectCounter: minRevertibleSideEffectCounter,
387
+ scopes: effectiveScopes,
388
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
389
+ // contract would perform, including setting senderForTags.
390
+ senderForTags: from,
323
391
  simulator,
324
- );
392
+ messageContextService: this.stateMachine.messageContextService,
393
+ });
325
394
 
326
395
  // 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
396
  let result: PrivateExecutionResult;
@@ -343,24 +412,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
343
412
  );
344
413
  const publicFunctionsCalldata = await Promise.all(
345
414
  publicCallRequests.map(async r => {
346
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
415
+ const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
347
416
  return new HashedValues(calldata, r.calldataHash);
348
417
  }),
349
418
  );
350
419
 
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);
420
+ noteCache.finish();
421
+ const nonceGenerator = noteCache.getNonceGenerator();
422
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
355
423
  } catch (err) {
356
424
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
357
425
  }
358
426
 
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);
427
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
428
+ // the nonce generator for the note hashes.
429
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
430
+ const { publicInputs } = await generateSimulatedProvingResult(
431
+ result,
432
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
433
+ this.stateMachine.node,
434
+ minRevertibleSideEffectCounter,
435
+ );
364
436
 
365
437
  const globals = makeGlobalVariables();
366
438
  globals.blockNumber = blockNumber;
@@ -371,17 +443,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
371
443
 
372
444
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
373
445
 
374
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
446
+ const bindings = this.logger.getBindings();
447
+ const contractsDB = new PublicContractsDB(
448
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
449
+ bindings,
450
+ );
375
451
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
452
+ const config = PublicSimulatorConfig.from({
453
+ skipFeeEnforcement: true,
454
+ collectDebugLogs: true,
455
+ collectHints: false,
456
+ collectStatistics: false,
457
+ collectCallMetadata: true,
458
+ });
376
459
  const processor = new PublicProcessor(
377
460
  globals,
378
461
  guardedMerkleTrees,
379
462
  contractsDB,
380
- new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
381
- doMerkleOperations: true,
382
- skipFeeEnforcement: true,
383
- }),
463
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
384
464
  new TestDateProvider(),
465
+ undefined,
466
+ createLogger('simulator:public-processor', bindings),
385
467
  );
386
468
 
387
469
  const tx = await Tx.create({
@@ -406,7 +488,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
406
488
  } else if (!processedTx.revertCode.isOK()) {
407
489
  if (processedTx.revertReason) {
408
490
  try {
409
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
491
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
410
492
  // eslint-disable-next-line no-empty
411
493
  } catch {}
412
494
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -435,13 +517,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
435
517
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
436
518
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
437
519
 
438
- const body = new Body([txEffect]);
439
-
440
- const l2Block = new L2Block(
441
- makeAppendOnlyTreeSnapshot(),
442
- await makeTXEBlockHeader(forkedWorldTrees, globals),
443
- body,
444
- );
520
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
445
521
 
446
522
  await this.stateMachine.handleL2Block(l2Block);
447
523
 
@@ -450,17 +526,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
450
526
  return executionResult.returnValues ?? [];
451
527
  }
452
528
 
453
- async txePublicCallNewFlow(
529
+ async publicCallNewFlow(
454
530
  from: AztecAddress,
455
531
  targetContractAddress: AztecAddress,
456
532
  calldata: Fr[],
457
533
  isStaticCall: boolean,
458
534
  ) {
459
535
  this.logger.verbose(
460
- `Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
536
+ `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
461
537
  );
462
538
 
463
- const blockNumber = await this.txeGetNextBlockNumber();
539
+ const blockNumber = await this.getNextBlockNumber();
464
540
 
465
541
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
466
542
 
@@ -470,7 +546,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
470
546
 
471
547
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
472
548
 
473
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
549
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
550
 
475
551
  const calldataHash = await computeCalldataHash(calldata);
476
552
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -484,22 +560,36 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
484
560
 
485
561
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
486
562
 
487
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
563
+ const bindings2 = this.logger.getBindings();
564
+ const contractsDB = new PublicContractsDB(
565
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
566
+ bindings2,
567
+ );
488
568
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
489
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
490
- doMerkleOperations: true,
569
+ const config = PublicSimulatorConfig.from({
491
570
  skipFeeEnforcement: true,
571
+ collectDebugLogs: true,
572
+ collectHints: false,
573
+ collectStatistics: false,
574
+ collectCallMetadata: true,
492
575
  });
493
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
576
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
577
+ const processor = new PublicProcessor(
578
+ globals,
579
+ guardedMerkleTrees,
580
+ contractsDB,
581
+ simulator,
582
+ new TestDateProvider(),
583
+ undefined,
584
+ createLogger('simulator:public-processor', bindings2),
585
+ );
494
586
 
495
587
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
496
588
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
497
589
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
498
590
  // unique.
499
591
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
500
- if (!isStaticCall) {
501
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
502
- }
592
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
503
593
 
504
594
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
505
595
  // may require producing reverts.
@@ -523,7 +613,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
523
613
  constantData,
524
614
  /*gasUsed=*/ new Gas(0, 0),
525
615
  /*feePayer=*/ AztecAddress.zero(),
526
- /*includeByTimestamp=*/ 0n,
616
+ /*expirationTimestamp=*/ 0n,
527
617
  inputsForPublic,
528
618
  undefined,
529
619
  );
@@ -550,7 +640,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
550
640
  } else if (!processedTx.revertCode.isOK()) {
551
641
  if (processedTx.revertReason) {
552
642
  try {
553
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
643
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
554
644
  // eslint-disable-next-line no-empty
555
645
  } catch {}
556
646
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -582,13 +672,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
582
672
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
583
673
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
584
674
 
585
- const body = new Body([txEffect]);
586
-
587
- const l2Block = new L2Block(
588
- makeAppendOnlyTreeSnapshot(),
589
- await makeTXEBlockHeader(forkedWorldTrees, globals),
590
- body,
591
- );
675
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
592
676
 
593
677
  await this.stateMachine.handleL2Block(l2Block);
594
678
 
@@ -597,23 +681,46 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
597
681
  return returnValues ?? [];
598
682
  }
599
683
 
600
- async txeSimulateUtilityFunction(
684
+ async executeUtilityFunction(
601
685
  targetContractAddress: AztecAddress,
602
686
  functionSelector: FunctionSelector,
603
687
  args: Fr[],
688
+ jobId: string,
604
689
  ) {
605
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
690
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
606
691
  if (!artifact) {
607
692
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
608
693
  }
609
694
 
610
- const call = {
695
+ // Sync notes before executing utility function to discover notes from previous transactions
696
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
697
+ await this.stateMachine.contractSyncService.ensureContractSynced(
698
+ targetContractAddress,
699
+ functionSelector,
700
+ async (call, execScopes) => {
701
+ await this.executeUtilityCall(call, execScopes, jobId);
702
+ },
703
+ blockHeader,
704
+ jobId,
705
+ 'ALL_SCOPES',
706
+ );
707
+
708
+ const call = FunctionCall.from({
611
709
  name: artifact.name,
612
- selector: functionSelector,
613
710
  to: targetContractAddress,
614
- };
711
+ selector: functionSelector,
712
+ type: FunctionType.UTILITY,
713
+ hideMsgSender: false,
714
+ isStatic: false,
715
+ args,
716
+ returnTypes: [],
717
+ });
718
+
719
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
720
+ }
615
721
 
616
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
722
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
723
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
617
724
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
618
725
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
619
726
  }
@@ -624,9 +731,28 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
624
731
  });
625
732
 
626
733
  try {
627
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
734
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
735
+ const oracle = new UtilityExecutionOracle({
736
+ contractAddress: call.to,
737
+ authWitnesses: [],
738
+ capsules: [],
739
+ anchorBlockHeader,
740
+ contractStore: this.contractStore,
741
+ noteStore: this.noteStore,
742
+ keyStore: this.keyStore,
743
+ addressStore: this.addressStore,
744
+ aztecNode: this.stateMachine.node,
745
+ recipientTaggingStore: this.recipientTaggingStore,
746
+ senderAddressBookStore: this.senderAddressBookStore,
747
+ capsuleStore: this.capsuleStore,
748
+ privateEventStore: this.privateEventStore,
749
+ messageContextService: this.stateMachine.messageContextService,
750
+ contractSyncService: this.contractSyncService,
751
+ jobId,
752
+ scopes,
753
+ });
628
754
  const acirExecutionResult = await new WASMSimulator()
629
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
755
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
630
756
  .catch((err: Error) => {
631
757
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
632
758
  throw new ExecutionError(
@@ -640,10 +766,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
640
766
  );
641
767
  });
642
768
 
643
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
769
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
644
770
  return witnessMapToFields(acirExecutionResult.returnWitness);
645
771
  } catch (err) {
646
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
772
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
647
773
  }
648
774
  }
649
775
 
@@ -652,7 +778,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
652
778
  return [this.nextBlockTimestamp, this.authwits];
653
779
  }
654
780
 
655
- private async getLastBlockNumber(): Promise<number> {
656
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
781
+ private async getLastBlockNumber(): Promise<BlockNumber> {
782
+ const header = await this.stateMachine.node.getBlockHeader('latest');
783
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
657
784
  }
658
785
  }