@aztec/txe 0.0.1-commit.5daedc8 → 0.0.1-commit.6201a7b05

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