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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dest/bin/index.d.ts +1 -1
  2. package/dest/constants.d.ts +3 -0
  3. package/dest/constants.d.ts.map +1 -0
  4. package/dest/constants.js +2 -0
  5. package/dest/index.d.ts +1 -1
  6. package/dest/index.d.ts.map +1 -1
  7. package/dest/index.js +85 -52
  8. package/dest/oracle/interfaces.d.ts +14 -10
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +10 -12
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +24 -15
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +205 -88
  16. package/dest/rpc_translator.d.ts +35 -20
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +151 -65
  19. package/dest/state_machine/archiver.d.ts +21 -51
  20. package/dest/state_machine/archiver.d.ts.map +1 -1
  21. package/dest/state_machine/archiver.js +63 -94
  22. package/dest/state_machine/dummy_p2p_client.d.ts +21 -14
  23. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  24. package/dest/state_machine/dummy_p2p_client.js +42 -22
  25. package/dest/state_machine/global_variable_builder.d.ts +6 -4
  26. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  27. package/dest/state_machine/global_variable_builder.js +13 -1
  28. package/dest/state_machine/index.d.ts +7 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +40 -23
  31. package/dest/state_machine/mock_epoch_cache.d.ts +14 -10
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +21 -13
  34. package/dest/state_machine/synchronizer.d.ts +3 -2
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +5 -4
  37. package/dest/txe_session.d.ts +26 -15
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +161 -53
  40. package/dest/util/encoding.d.ts +615 -16
  41. package/dest/util/encoding.d.ts.map +1 -1
  42. package/dest/util/encoding.js +1 -1
  43. package/dest/util/expected_failure_error.d.ts +1 -1
  44. package/dest/util/expected_failure_error.d.ts.map +1 -1
  45. package/dest/util/txe_account_store.d.ts +10 -0
  46. package/dest/util/txe_account_store.d.ts.map +1 -0
  47. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  48. package/dest/util/txe_public_contract_data_source.d.ts +8 -8
  49. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  50. package/dest/util/txe_public_contract_data_source.js +12 -29
  51. package/dest/utils/block_creation.d.ts +21 -6
  52. package/dest/utils/block_creation.d.ts.map +1 -1
  53. package/dest/utils/block_creation.js +38 -4
  54. package/dest/utils/tx_effect_creation.d.ts +3 -3
  55. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  56. package/dest/utils/tx_effect_creation.js +4 -7
  57. package/package.json +18 -17
  58. package/src/constants.ts +3 -0
  59. package/src/index.ts +97 -60
  60. package/src/oracle/interfaces.ts +16 -8
  61. package/src/oracle/txe_oracle_public_context.ts +12 -19
  62. package/src/oracle/txe_oracle_top_level_context.ts +249 -127
  63. package/src/rpc_translator.ts +179 -68
  64. package/src/state_machine/archiver.ts +63 -117
  65. package/src/state_machine/dummy_p2p_client.ts +59 -29
  66. package/src/state_machine/global_variable_builder.ts +22 -4
  67. package/src/state_machine/index.ts +60 -21
  68. package/src/state_machine/mock_epoch_cache.ts +25 -20
  69. package/src/state_machine/synchronizer.ts +6 -5
  70. package/src/txe_session.ts +222 -101
  71. package/src/util/encoding.ts +1 -1
  72. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  73. package/src/util/txe_public_contract_data_source.ts +20 -45
  74. package/src/utils/block_creation.ts +49 -14
  75. package/src/utils/tx_effect_creation.ts +5 -12
  76. package/dest/util/txe_account_data_provider.d.ts +0 -10
  77. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  78. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  79. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  80. package/dest/util/txe_contract_data_provider.js +0 -22
  81. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -1,34 +1,41 @@
1
1
  import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
- import { Schnorr } from '@aztec/foundation/crypto';
3
- import { Fr } from '@aztec/foundation/fields';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { Schnorr } from '@aztec/foundation/crypto/schnorr';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
5
6
  import { TestDateProvider } from '@aztec/foundation/timer';
6
7
  import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
7
8
  import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
8
9
  import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
9
- import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, PublicTxSimulator } from '@aztec/simulator/server';
10
- import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
10
+ import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
11
+ import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
11
12
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
13
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
12
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { Body, L2Block } from '@aztec/stdlib/block';
14
15
  import { computePartialAddress } from '@aztec/stdlib/contract';
15
16
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
16
- import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
17
+ import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
17
18
  import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
18
19
  import { ChonkProof } from '@aztec/stdlib/proofs';
19
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
20
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
20
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
21
22
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
22
23
  import { ForkCheckpoint } from '@aztec/world-state';
24
+ import { DEFAULT_ADDRESS } from '../constants.js';
23
25
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
24
- import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from '../utils/block_creation.js';
26
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
25
27
  export class TXEOracleTopLevelContext {
26
28
  stateMachine;
27
- contractDataProvider;
29
+ contractStore;
30
+ noteStore;
28
31
  keyStore;
29
- addressDataProvider;
30
- accountDataProvider;
31
- pxeOracleInterface;
32
+ addressStore;
33
+ accountStore;
34
+ senderTaggingStore;
35
+ recipientTaggingStore;
36
+ senderAddressBookStore;
37
+ capsuleStore;
38
+ privateEventStore;
32
39
  nextBlockTimestamp;
33
40
  version;
34
41
  chainId;
@@ -36,13 +43,18 @@ export class TXEOracleTopLevelContext {
36
43
  isMisc;
37
44
  isTxe;
38
45
  logger;
39
- constructor(stateMachine, contractDataProvider, keyStore, addressDataProvider, accountDataProvider, pxeOracleInterface, nextBlockTimestamp, version, chainId, authwits){
46
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits){
40
47
  this.stateMachine = stateMachine;
41
- this.contractDataProvider = contractDataProvider;
48
+ this.contractStore = contractStore;
49
+ this.noteStore = noteStore;
42
50
  this.keyStore = keyStore;
43
- this.addressDataProvider = addressDataProvider;
44
- this.accountDataProvider = accountDataProvider;
45
- this.pxeOracleInterface = pxeOracleInterface;
51
+ this.addressStore = addressStore;
52
+ this.accountStore = accountStore;
53
+ this.senderTaggingStore = senderTaggingStore;
54
+ this.recipientTaggingStore = recipientTaggingStore;
55
+ this.senderAddressBookStore = senderAddressBookStore;
56
+ this.capsuleStore = capsuleStore;
57
+ this.privateEventStore = privateEventStore;
46
58
  this.nextBlockTimestamp = nextBlockTimestamp;
47
59
  this.version = version;
48
60
  this.chainId = chainId;
@@ -63,17 +75,21 @@ export class TXEOracleTopLevelContext {
63
75
  return Fr.random();
64
76
  }
65
77
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
66
- utilityDebugLog(level, message, fields) {
78
+ utilityLog(level, message, fields) {
67
79
  if (!LogLevels[level]) {
68
- throw new Error(`Invalid debug log level: ${level}`);
80
+ throw new Error(`Invalid log level: ${level}`);
69
81
  }
70
82
  const levelName = LogLevels[level];
71
83
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
72
84
  module: `${this.logger.module}:debug_log`
73
85
  });
86
+ return Promise.resolve();
87
+ }
88
+ txeGetDefaultAddress() {
89
+ return DEFAULT_ADDRESS;
74
90
  }
75
91
  async txeGetNextBlockNumber() {
76
- return await this.getLastBlockNumber() + 1;
92
+ return BlockNumber(await this.getLastBlockNumber() + 1);
77
93
  }
78
94
  txeGetNextBlockTimestamp() {
79
95
  return Promise.resolve(this.nextBlockTimestamp);
@@ -82,7 +98,8 @@ export class TXEOracleTopLevelContext {
82
98
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
83
99
  }
84
100
  async txeGetLastTxEffects() {
85
- const block = await this.stateMachine.archiver.getBlock('latest');
101
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
102
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
86
103
  if (block.body.txEffects.length != 1) {
87
104
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
88
105
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
@@ -94,6 +111,28 @@ export class TXEOracleTopLevelContext {
94
111
  nullifiers: txEffects.nullifiers
95
112
  };
96
113
  }
114
+ async syncContractNonOracleMethod(contractAddress, scope, jobId) {
115
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
116
+ this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
117
+ return;
118
+ }
119
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
120
+ await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
121
+ await this.executeUtilityCall(call, execScopes, jobId);
122
+ }, blockHeader, jobId, [
123
+ scope
124
+ ]);
125
+ }
126
+ async txeGetPrivateEvents(selector, contractAddress, scope) {
127
+ return (await this.privateEventStore.getPrivateEvents(selector, {
128
+ contractAddress,
129
+ scopes: [
130
+ scope
131
+ ],
132
+ fromBlock: 0,
133
+ toBlock: await this.getLastBlockNumber() + 1
134
+ })).map((e)=>e.packedEvent);
135
+ }
97
136
  async txeAdvanceBlocksBy(blocks) {
98
137
  this.logger.debug(`time traveling ${blocks} blocks`);
99
138
  for(let i = 0; i < blocks; i++){
@@ -114,32 +153,32 @@ export class TXEOracleTopLevelContext {
114
153
  if (!secret.equals(Fr.ZERO)) {
115
154
  await this.txeAddAccount(artifact, instance, secret);
116
155
  } else {
117
- await this.contractDataProvider.addContractInstance(instance);
118
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
156
+ await this.contractStore.addContractInstance(instance);
157
+ await this.contractStore.addContractArtifact(artifact);
119
158
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
120
159
  }
121
160
  }
122
161
  async txeAddAccount(artifact, instance, secret) {
123
162
  const partialAddress = await computePartialAddress(instance);
124
163
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
125
- await this.contractDataProvider.addContractInstance(instance);
126
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
164
+ await this.contractStore.addContractInstance(instance);
165
+ await this.contractStore.addContractArtifact(artifact);
127
166
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
128
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
129
- await this.addressDataProvider.addCompleteAddress(completeAddress);
167
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
168
+ await this.addressStore.addCompleteAddress(completeAddress);
130
169
  this.logger.debug(`Created account ${completeAddress.address}`);
131
170
  return completeAddress;
132
171
  }
133
172
  async txeCreateAccount(secret) {
134
- // This is a footgun !
173
+ // This is a foot gun !
135
174
  const completeAddress = await this.keyStore.addAccount(secret, secret);
136
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
137
- await this.addressDataProvider.addCompleteAddress(completeAddress);
175
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
176
+ await this.addressStore.addCompleteAddress(completeAddress);
138
177
  this.logger.debug(`Created account ${completeAddress.address}`);
139
178
  return completeAddress;
140
179
  }
141
180
  async txeAddAuthWitness(address, messageHash) {
142
- const account = await this.accountDataProvider.getAccount(address);
181
+ const account = await this.accountStore.getAccount(address);
143
182
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
144
183
  const schnorr = new Schnorr();
145
184
  const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
@@ -158,42 +197,85 @@ export class TXEOracleTopLevelContext {
158
197
  txEffect.txHash = new TxHash(new Fr(blockNumber));
159
198
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
160
199
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
161
- const block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, makeGlobalVariables(undefined, {
200
+ const globals = makeGlobalVariables(undefined, {
162
201
  blockNumber,
163
202
  timestamp: this.nextBlockTimestamp,
164
203
  version: this.version,
165
204
  chainId: this.chainId
166
- })), new Body([
205
+ });
206
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [
167
207
  txEffect
168
- ]));
208
+ ]);
169
209
  await forkedWorldTrees.close();
170
210
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
171
211
  await this.stateMachine.handleL2Block(block);
172
212
  }
173
- async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
174
- this.logger.verbose(`Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
175
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
213
+ async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
214
+ this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
215
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
176
216
  if (!artifact) {
177
217
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
178
218
  throw new Error(message);
179
219
  }
220
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
221
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
222
+ const effectiveScopes = from.isZero() ? [] : [
223
+ from
224
+ ];
225
+ // Sync notes before executing private function to discover notes from previous transactions
226
+ const utilityExecutor = async (call, execScopes)=>{
227
+ await this.executeUtilityCall(call, execScopes, jobId);
228
+ };
229
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
230
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
180
231
  const blockNumber = await this.txeGetNextBlockNumber();
181
232
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
182
233
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
183
234
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
184
235
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
185
236
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
186
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
187
- const txRequestHash = getSingleTxBlockRequestHash(blockNumber);
188
- const noteCache = new ExecutionNoteCache(txRequestHash);
237
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
238
+ const noteCache = new ExecutionNoteCache(protocolNullifier);
239
+ // In production, the account contract sets the min revertible counter before calling the app function.
240
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
241
+ // marking all side effects as revertible.
242
+ const minRevertibleSideEffectCounter = 1;
243
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
189
244
  const taggingIndexCache = new ExecutionTaggingIndexCache();
190
245
  const simulator = new WASMSimulator();
191
- const privateExecutionOracle = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ Array.from(this.authwits.values()), /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create([
192
- new HashedValues(args, argsHash)
193
- ]), noteCache, taggingIndexCache, this.pxeOracleInterface, 0, 1, undefined, undefined, /**
194
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
195
- * contract would perform, including setting senderForTags.
196
- */ from, simulator);
246
+ const privateExecutionOracle = new PrivateExecutionOracle({
247
+ argsHash,
248
+ txContext,
249
+ callContext,
250
+ anchorBlockHeader: blockHeader,
251
+ utilityExecutor,
252
+ authWitnesses: Array.from(this.authwits.values()),
253
+ capsules: [],
254
+ executionCache: HashedValuesCache.create([
255
+ new HashedValues(args, argsHash)
256
+ ]),
257
+ noteCache,
258
+ taggingIndexCache,
259
+ contractStore: this.contractStore,
260
+ noteStore: this.noteStore,
261
+ keyStore: this.keyStore,
262
+ addressStore: this.addressStore,
263
+ aztecNode: this.stateMachine.node,
264
+ senderTaggingStore: this.senderTaggingStore,
265
+ recipientTaggingStore: this.recipientTaggingStore,
266
+ senderAddressBookStore: this.senderAddressBookStore,
267
+ capsuleStore: this.capsuleStore,
268
+ privateEventStore: this.privateEventStore,
269
+ contractSyncService: this.stateMachine.contractSyncService,
270
+ jobId,
271
+ totalPublicCalldataCount: 0,
272
+ sideEffectCounter: minRevertibleSideEffectCounter,
273
+ scopes: effectiveScopes,
274
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
275
+ // contract would perform, including setting senderForTags.
276
+ senderForTags: from,
277
+ simulator
278
+ });
197
279
  // 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.
198
280
  let result;
199
281
  let executionResult;
@@ -208,18 +290,16 @@ export class TXEOracleTopLevelContext {
208
290
  const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
209
291
  return new HashedValues(calldata, r.calldataHash);
210
292
  }));
211
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
212
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
213
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
214
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
293
+ noteCache.finish();
294
+ const nonceGenerator = noteCache.getNonceGenerator();
295
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
215
296
  } catch (err) {
216
297
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
217
298
  }
218
- // According to the protocol rules, the nonce generator for the note hashes
219
- // can either be the first nullifier in the tx or the hash of the initial tx request
220
- // if there are none.
221
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? txRequestHash : result.firstNullifier;
222
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
299
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
300
+ // the nonce generator for the note hashes.
301
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
302
+ const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
223
303
  const globals = makeGlobalVariables();
224
304
  globals.blockNumber = blockNumber;
225
305
  globals.timestamp = this.nextBlockTimestamp;
@@ -227,12 +307,17 @@ export class TXEOracleTopLevelContext {
227
307
  globals.version = this.version;
228
308
  globals.gasFees = GasFees.empty();
229
309
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
230
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
310
+ const bindings = this.logger.getBindings();
311
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
231
312
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
232
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
233
- doMerkleOperations: true,
234
- skipFeeEnforcement: true
235
- }), new TestDateProvider());
313
+ const config = PublicSimulatorConfig.from({
314
+ skipFeeEnforcement: true,
315
+ collectDebugLogs: true,
316
+ collectHints: false,
317
+ collectStatistics: false,
318
+ collectCallMetadata: true
319
+ });
320
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
236
321
  const tx = await Tx.create({
237
322
  data: publicInputs,
238
323
  chonkProof: ChonkProof.empty(),
@@ -253,7 +338,7 @@ export class TXEOracleTopLevelContext {
253
338
  } else if (!processedTx.revertCode.isOK()) {
254
339
  if (processedTx.revertReason) {
255
340
  try {
256
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
341
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
257
342
  // eslint-disable-next-line no-empty
258
343
  } catch {}
259
344
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -275,22 +360,21 @@ export class TXEOracleTopLevelContext {
275
360
  txEffect.txHash = new TxHash(new Fr(blockNumber));
276
361
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
277
362
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
278
- const body = new Body([
363
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
279
364
  txEffect
280
365
  ]);
281
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
282
366
  await this.stateMachine.handleL2Block(l2Block);
283
367
  await forkedWorldTrees.close();
284
368
  return executionResult.returnValues ?? [];
285
369
  }
286
370
  async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
287
- this.logger.verbose(`Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
371
+ this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
288
372
  const blockNumber = await this.txeGetNextBlockNumber();
289
373
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
290
374
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
291
375
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
292
376
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
293
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
377
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
294
378
  const calldataHash = await computeCalldataHash(calldata);
295
379
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
296
380
  const globals = makeGlobalVariables();
@@ -300,28 +384,31 @@ export class TXEOracleTopLevelContext {
300
384
  globals.version = this.version;
301
385
  globals.gasFees = GasFees.empty();
302
386
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
303
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
387
+ const bindings2 = this.logger.getBindings();
388
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
304
389
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
305
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
306
- doMerkleOperations: true,
307
- skipFeeEnforcement: true
390
+ const config = PublicSimulatorConfig.from({
391
+ skipFeeEnforcement: true,
392
+ collectDebugLogs: true,
393
+ collectHints: false,
394
+ collectStatistics: false,
395
+ collectCallMetadata: true
308
396
  });
309
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
397
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
398
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
310
399
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
311
400
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
312
401
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
313
402
  // unique.
314
403
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
315
- if (!isStaticCall) {
316
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
317
- }
404
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
318
405
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
319
406
  // may require producing reverts.
320
407
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
321
408
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
322
409
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
323
410
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
324
- const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
411
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
325
412
  const tx = await Tx.create({
326
413
  data: txData,
327
414
  chonkProof: ChonkProof.empty(),
@@ -344,7 +431,7 @@ export class TXEOracleTopLevelContext {
344
431
  } else if (!processedTx.revertCode.isOK()) {
345
432
  if (processedTx.revertReason) {
346
433
  try {
347
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
434
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
348
435
  // eslint-disable-next-line no-empty
349
436
  } catch {}
350
437
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -367,25 +454,37 @@ export class TXEOracleTopLevelContext {
367
454
  txEffect.txHash = new TxHash(new Fr(blockNumber));
368
455
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
369
456
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
370
- const body = new Body([
457
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
371
458
  txEffect
372
459
  ]);
373
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
374
460
  await this.stateMachine.handleL2Block(l2Block);
375
461
  await forkedWorldTrees.close();
376
462
  return returnValues ?? [];
377
463
  }
378
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
379
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
464
+ async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
465
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
380
466
  if (!artifact) {
381
467
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
382
468
  }
383
- const call = {
469
+ // Sync notes before executing utility function to discover notes from previous transactions
470
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
471
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
472
+ await this.executeUtilityCall(call, execScopes, jobId);
473
+ }, blockHeader, jobId, 'ALL_SCOPES');
474
+ const call = FunctionCall.from({
384
475
  name: artifact.name,
476
+ to: targetContractAddress,
385
477
  selector: functionSelector,
386
- to: targetContractAddress
387
- };
388
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
478
+ type: FunctionType.UTILITY,
479
+ hideMsgSender: false,
480
+ isStatic: false,
481
+ args,
482
+ returnTypes: []
483
+ });
484
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
485
+ }
486
+ async executeUtilityCall(call, scopes, jobId) {
487
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
389
488
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
390
489
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
391
490
  }
@@ -394,8 +493,25 @@ export class TXEOracleTopLevelContext {
394
493
  selector: call.selector
395
494
  });
396
495
  try {
397
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
398
- const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
496
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
497
+ const oracle = new UtilityExecutionOracle({
498
+ contractAddress: call.to,
499
+ authWitnesses: [],
500
+ capsules: [],
501
+ anchorBlockHeader,
502
+ contractStore: this.contractStore,
503
+ noteStore: this.noteStore,
504
+ keyStore: this.keyStore,
505
+ addressStore: this.addressStore,
506
+ aztecNode: this.stateMachine.node,
507
+ recipientTaggingStore: this.recipientTaggingStore,
508
+ senderAddressBookStore: this.senderAddressBookStore,
509
+ capsuleStore: this.capsuleStore,
510
+ privateEventStore: this.privateEventStore,
511
+ jobId,
512
+ scopes
513
+ });
514
+ const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
399
515
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
400
516
  throw new ExecutionError(err.message, {
401
517
  contractAddress: call.to,
@@ -404,10 +520,10 @@ export class TXEOracleTopLevelContext {
404
520
  cause: err
405
521
  });
406
522
  });
407
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
523
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
408
524
  return witnessMapToFields(acirExecutionResult.returnWitness);
409
525
  } catch (err) {
410
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
526
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
411
527
  }
412
528
  }
413
529
  close() {
@@ -418,6 +534,7 @@ export class TXEOracleTopLevelContext {
418
534
  ];
419
535
  }
420
536
  async getLastBlockNumber() {
421
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
537
+ const header = await this.stateMachine.node.getBlockHeader('latest');
538
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
422
539
  }
423
540
  }