@aztec/txe 0.0.1-commit.9b94fc1 → 0.0.1-commit.9ee6fcc6

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