@aztec/txe 0.0.1-commit.5476d83 → 0.0.1-commit.5914bae

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