@aztec/txe 0.0.1-commit.03f7ef2 → 0.0.1-commit.04852196a

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 (74) 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 +88 -54
  7. package/dest/oracle/interfaces.d.ts +29 -28
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +13 -13
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +16 -16
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +33 -31
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +179 -92
  15. package/dest/rpc_translator.d.ts +87 -81
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +291 -173
  18. package/dest/state_machine/archiver.d.ts +20 -67
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +59 -178
  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 +39 -24
  24. package/dest/state_machine/global_variable_builder.d.ts +2 -2
  25. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  26. package/dest/state_machine/global_variable_builder.js +1 -1
  27. package/dest/state_machine/index.d.ts +6 -6
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +37 -14
  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 +3 -3
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/txe_session.d.ts +22 -16
  36. package/dest/txe_session.d.ts.map +1 -1
  37. package/dest/txe_session.js +153 -56
  38. package/dest/util/encoding.d.ts +17 -17
  39. package/dest/util/txe_account_store.d.ts +10 -0
  40. package/dest/util/txe_account_store.d.ts.map +1 -0
  41. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  42. package/dest/util/txe_public_contract_data_source.d.ts +5 -6
  43. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  44. package/dest/util/txe_public_contract_data_source.js +12 -29
  45. package/dest/utils/block_creation.d.ts +4 -4
  46. package/dest/utils/block_creation.d.ts.map +1 -1
  47. package/dest/utils/block_creation.js +18 -5
  48. package/dest/utils/tx_effect_creation.d.ts +2 -3
  49. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  50. package/dest/utils/tx_effect_creation.js +3 -6
  51. package/package.json +16 -16
  52. package/src/constants.ts +3 -0
  53. package/src/index.ts +89 -52
  54. package/src/oracle/interfaces.ts +32 -31
  55. package/src/oracle/txe_oracle_public_context.ts +16 -18
  56. package/src/oracle/txe_oracle_top_level_context.ts +217 -133
  57. package/src/rpc_translator.ts +309 -185
  58. package/src/state_machine/archiver.ts +54 -220
  59. package/src/state_machine/dummy_p2p_client.ts +55 -32
  60. package/src/state_machine/global_variable_builder.ts +1 -1
  61. package/src/state_machine/index.ts +50 -12
  62. package/src/state_machine/mock_epoch_cache.ts +15 -11
  63. package/src/state_machine/synchronizer.ts +2 -2
  64. package/src/txe_session.ts +207 -120
  65. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  66. package/src/util/txe_public_contract_data_source.ts +16 -42
  67. package/src/utils/block_creation.ts +19 -16
  68. package/src/utils/tx_effect_creation.ts +3 -11
  69. package/dest/util/txe_account_data_provider.d.ts +0 -10
  70. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  71. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  72. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  73. package/dest/util/txe_contract_data_provider.js +0 -22
  74. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -8,7 +8,7 @@ import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
8
8
  import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
9
9
  import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
10
10
  import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
11
- import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
11
+ import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
12
12
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
13
13
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
14
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
@@ -21,20 +21,21 @@ import { makeGlobalVariables } from '@aztec/stdlib/testing';
21
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
22
22
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
23
23
  import { ForkCheckpoint } from '@aztec/world-state';
24
- import { DEFAULT_ADDRESS } from '../txe_session.js';
24
+ import { DEFAULT_ADDRESS } from '../constants.js';
25
25
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
26
26
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
27
27
  export class TXEOracleTopLevelContext {
28
28
  stateMachine;
29
- contractDataProvider;
30
- noteDataProvider;
29
+ contractStore;
30
+ noteStore;
31
31
  keyStore;
32
- addressDataProvider;
33
- accountDataProvider;
34
- senderTaggingDataProvider;
35
- recipientTaggingDataProvider;
36
- capsuleDataProvider;
37
- privateEventDataProvider;
32
+ addressStore;
33
+ accountStore;
34
+ senderTaggingStore;
35
+ recipientTaggingStore;
36
+ senderAddressBookStore;
37
+ capsuleStore;
38
+ privateEventStore;
38
39
  nextBlockTimestamp;
39
40
  version;
40
41
  chainId;
@@ -42,17 +43,18 @@ export class TXEOracleTopLevelContext {
42
43
  isMisc;
43
44
  isTxe;
44
45
  logger;
45
- constructor(stateMachine, contractDataProvider, noteDataProvider, keyStore, addressDataProvider, accountDataProvider, senderTaggingDataProvider, recipientTaggingDataProvider, capsuleDataProvider, privateEventDataProvider, nextBlockTimestamp, version, chainId, authwits){
46
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits){
46
47
  this.stateMachine = stateMachine;
47
- this.contractDataProvider = contractDataProvider;
48
- this.noteDataProvider = noteDataProvider;
48
+ this.contractStore = contractStore;
49
+ this.noteStore = noteStore;
49
50
  this.keyStore = keyStore;
50
- this.addressDataProvider = addressDataProvider;
51
- this.accountDataProvider = accountDataProvider;
52
- this.senderTaggingDataProvider = senderTaggingDataProvider;
53
- this.recipientTaggingDataProvider = recipientTaggingDataProvider;
54
- this.capsuleDataProvider = capsuleDataProvider;
55
- this.privateEventDataProvider = privateEventDataProvider;
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;
56
58
  this.nextBlockTimestamp = nextBlockTimestamp;
57
59
  this.version = version;
58
60
  this.chainId = chainId;
@@ -62,40 +64,42 @@ export class TXEOracleTopLevelContext {
62
64
  this.logger = createLogger('txe:top_level_context');
63
65
  this.logger.debug('Entering Top Level Context');
64
66
  }
65
- utilityAssertCompatibleOracleVersion(version) {
67
+ assertCompatibleOracleVersion(version) {
66
68
  if (version !== ORACLE_VERSION) {
67
69
  throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
68
70
  }
69
71
  }
70
72
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
71
73
  // setup.
72
- utilityGetRandomField() {
74
+ getRandomField() {
73
75
  return Fr.random();
74
76
  }
75
77
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
76
- utilityDebugLog(level, message, fields) {
78
+ log(level, message, fields) {
77
79
  if (!LogLevels[level]) {
78
- throw new Error(`Invalid debug log level: ${level}`);
80
+ throw new Error(`Invalid log level: ${level}`);
79
81
  }
80
82
  const levelName = LogLevels[level];
81
83
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
82
84
  module: `${this.logger.module}:debug_log`
83
85
  });
86
+ return Promise.resolve();
84
87
  }
85
- txeGetDefaultAddress() {
88
+ getDefaultAddress() {
86
89
  return DEFAULT_ADDRESS;
87
90
  }
88
- async txeGetNextBlockNumber() {
91
+ async getNextBlockNumber() {
89
92
  return BlockNumber(await this.getLastBlockNumber() + 1);
90
93
  }
91
- txeGetNextBlockTimestamp() {
94
+ getNextBlockTimestamp() {
92
95
  return Promise.resolve(this.nextBlockTimestamp);
93
96
  }
94
- async txeGetLastBlockTimestamp() {
97
+ async getLastBlockTimestamp() {
95
98
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
96
99
  }
97
- async txeGetLastTxEffects() {
98
- const block = await this.stateMachine.archiver.getL2Block('latest');
100
+ async getLastTxEffects() {
101
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
102
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
99
103
  if (block.body.txEffects.length != 1) {
100
104
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
101
105
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
@@ -107,8 +111,20 @@ export class TXEOracleTopLevelContext {
107
111
  nullifiers: txEffects.nullifiers
108
112
  };
109
113
  }
110
- async txeGetPrivateEvents(selector, contractAddress, scope) {
111
- return (await this.privateEventDataProvider.getPrivateEvents(selector, {
114
+ async syncContractNonOracleMethod(contractAddress, scope, jobId) {
115
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
116
+ this.logger.debug(`Skipping sync in getPrivateEvents 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 getPrivateEvents(selector, contractAddress, scope) {
127
+ return (await this.privateEventStore.getPrivateEvents(selector, {
112
128
  contractAddress,
113
129
  scopes: [
114
130
  scope
@@ -117,17 +133,17 @@ export class TXEOracleTopLevelContext {
117
133
  toBlock: await this.getLastBlockNumber() + 1
118
134
  })).map((e)=>e.packedEvent);
119
135
  }
120
- async txeAdvanceBlocksBy(blocks) {
136
+ async advanceBlocksBy(blocks) {
121
137
  this.logger.debug(`time traveling ${blocks} blocks`);
122
138
  for(let i = 0; i < blocks; i++){
123
139
  await this.mineBlock();
124
140
  }
125
141
  }
126
- txeAdvanceTimestampBy(duration) {
142
+ advanceTimestampBy(duration) {
127
143
  this.logger.debug(`time traveling ${duration} seconds`);
128
144
  this.nextBlockTimestamp += duration;
129
145
  }
130
- async txeDeploy(artifact, instance, secret) {
146
+ async deploy(artifact, instance, secret) {
131
147
  // Emit deployment nullifier
132
148
  await this.mineBlock({
133
149
  nullifiers: [
@@ -135,34 +151,34 @@ export class TXEOracleTopLevelContext {
135
151
  ]
136
152
  });
137
153
  if (!secret.equals(Fr.ZERO)) {
138
- await this.txeAddAccount(artifact, instance, secret);
154
+ await this.addAccount(artifact, instance, secret);
139
155
  } else {
140
- await this.contractDataProvider.addContractInstance(instance);
141
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
156
+ await this.contractStore.addContractInstance(instance);
157
+ await this.contractStore.addContractArtifact(artifact);
142
158
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
143
159
  }
144
160
  }
145
- async txeAddAccount(artifact, instance, secret) {
161
+ async addAccount(artifact, instance, secret) {
146
162
  const partialAddress = await computePartialAddress(instance);
147
163
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
148
- await this.contractDataProvider.addContractInstance(instance);
149
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
164
+ await this.contractStore.addContractInstance(instance);
165
+ await this.contractStore.addContractArtifact(artifact);
150
166
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
151
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
152
- await this.addressDataProvider.addCompleteAddress(completeAddress);
167
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
168
+ await this.addressStore.addCompleteAddress(completeAddress);
153
169
  this.logger.debug(`Created account ${completeAddress.address}`);
154
170
  return completeAddress;
155
171
  }
156
- async txeCreateAccount(secret) {
172
+ async createAccount(secret) {
157
173
  // This is a foot gun !
158
174
  const completeAddress = await this.keyStore.addAccount(secret, secret);
159
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
160
- await this.addressDataProvider.addCompleteAddress(completeAddress);
175
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
176
+ await this.addressStore.addCompleteAddress(completeAddress);
161
177
  this.logger.debug(`Created account ${completeAddress.address}`);
162
178
  return completeAddress;
163
179
  }
164
- async txeAddAuthWitness(address, messageHash) {
165
- const account = await this.accountDataProvider.getAccount(address);
180
+ async addAuthWitness(address, messageHash) {
181
+ const account = await this.accountStore.getAccount(address);
166
182
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
167
183
  const schnorr = new Schnorr();
168
184
  const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
@@ -172,7 +188,7 @@ export class TXEOracleTopLevelContext {
172
188
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
173
189
  }
174
190
  async mineBlock(options = {}) {
175
- const blockNumber = await this.txeGetNextBlockNumber();
191
+ const blockNumber = await this.getNextBlockNumber();
176
192
  const txEffect = TxEffect.empty();
177
193
  txEffect.nullifiers = [
178
194
  getSingleTxBlockRequestHash(blockNumber),
@@ -194,30 +210,72 @@ export class TXEOracleTopLevelContext {
194
210
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
195
211
  await this.stateMachine.handleL2Block(block);
196
212
  }
197
- async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
198
- this.logger.verbose(`Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
199
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
213
+ async privateCallNewFlow(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);
200
216
  if (!artifact) {
201
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';
202
218
  throw new Error(message);
203
219
  }
204
- const blockNumber = await this.txeGetNextBlockNumber();
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);
231
+ const blockNumber = await this.getNextBlockNumber();
205
232
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
206
233
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
207
234
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
208
235
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
209
236
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
210
- const blockHeader = await this.stateMachine.anchorBlockDataProvider.getBlockHeader();
211
237
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
212
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);
213
244
  const taggingIndexCache = new ExecutionTaggingIndexCache();
214
245
  const simulator = new WASMSimulator();
215
- 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([
216
- new HashedValues(args, argsHash)
217
- ]), noteCache, taggingIndexCache, this.contractDataProvider, this.noteDataProvider, this.keyStore, this.addressDataProvider, this.stateMachine.node, this.stateMachine.anchorBlockDataProvider, this.senderTaggingDataProvider, this.recipientTaggingDataProvider, this.capsuleDataProvider, this.privateEventDataProvider, 0, 1, undefined, undefined, /**
218
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
219
- * contract would perform, including setting senderForTags.
220
- */ 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
+ });
221
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.
222
280
  let result;
223
281
  let executionResult;
@@ -229,21 +287,19 @@ export class TXEOracleTopLevelContext {
229
287
  r.publicInputs.publicTeardownCallRequest
230
288
  ]));
231
289
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
232
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
290
+ const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
233
291
  return new HashedValues(calldata, r.calldataHash);
234
292
  }));
235
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
236
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
237
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
238
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
293
+ noteCache.finish();
294
+ const nonceGenerator = noteCache.getNonceGenerator();
295
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
239
296
  } catch (err) {
240
297
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
241
298
  }
242
- // According to the protocol rules, the nonce generator for the note hashes
243
- // can either be the first nullifier in the tx or the hash of the initial tx request
244
- // if there are none.
245
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
246
- 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);
247
303
  const globals = makeGlobalVariables();
248
304
  globals.blockNumber = blockNumber;
249
305
  globals.timestamp = this.nextBlockTimestamp;
@@ -251,7 +307,8 @@ export class TXEOracleTopLevelContext {
251
307
  globals.version = this.version;
252
308
  globals.gasFees = GasFees.empty();
253
309
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
254
- 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);
255
312
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
256
313
  const config = PublicSimulatorConfig.from({
257
314
  skipFeeEnforcement: true,
@@ -260,7 +317,7 @@ export class TXEOracleTopLevelContext {
260
317
  collectStatistics: false,
261
318
  collectCallMetadata: true
262
319
  });
263
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config), new TestDateProvider());
320
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
264
321
  const tx = await Tx.create({
265
322
  data: publicInputs,
266
323
  chonkProof: ChonkProof.empty(),
@@ -281,7 +338,7 @@ export class TXEOracleTopLevelContext {
281
338
  } else if (!processedTx.revertCode.isOK()) {
282
339
  if (processedTx.revertReason) {
283
340
  try {
284
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
341
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
285
342
  // eslint-disable-next-line no-empty
286
343
  } catch {}
287
344
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -310,14 +367,14 @@ export class TXEOracleTopLevelContext {
310
367
  await forkedWorldTrees.close();
311
368
  return executionResult.returnValues ?? [];
312
369
  }
313
- async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
314
- this.logger.verbose(`Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
315
- const blockNumber = await this.txeGetNextBlockNumber();
370
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
371
+ this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
372
+ const blockNumber = await this.getNextBlockNumber();
316
373
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
317
374
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
318
375
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
319
376
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
320
- const anchorBlockHeader = await this.stateMachine.anchorBlockDataProvider.getBlockHeader();
377
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
321
378
  const calldataHash = await computeCalldataHash(calldata);
322
379
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
323
380
  const globals = makeGlobalVariables();
@@ -327,7 +384,8 @@ export class TXEOracleTopLevelContext {
327
384
  globals.version = this.version;
328
385
  globals.gasFees = GasFees.empty();
329
386
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
330
- 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);
331
389
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
332
390
  const config = PublicSimulatorConfig.from({
333
391
  skipFeeEnforcement: true,
@@ -336,8 +394,8 @@ export class TXEOracleTopLevelContext {
336
394
  collectStatistics: false,
337
395
  collectCallMetadata: true
338
396
  });
339
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
340
- 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));
341
399
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
342
400
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
343
401
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
@@ -350,7 +408,7 @@ export class TXEOracleTopLevelContext {
350
408
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
351
409
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
352
410
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
353
- 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);
354
412
  const tx = await Tx.create({
355
413
  data: txData,
356
414
  chonkProof: ChonkProof.empty(),
@@ -373,7 +431,7 @@ export class TXEOracleTopLevelContext {
373
431
  } else if (!processedTx.revertCode.isOK()) {
374
432
  if (processedTx.revertReason) {
375
433
  try {
376
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
434
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
377
435
  // eslint-disable-next-line no-empty
378
436
  } catch {}
379
437
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -403,17 +461,30 @@ export class TXEOracleTopLevelContext {
403
461
  await forkedWorldTrees.close();
404
462
  return returnValues ?? [];
405
463
  }
406
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
407
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
464
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
465
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
408
466
  if (!artifact) {
409
467
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
410
468
  }
411
- 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({
412
475
  name: artifact.name,
476
+ to: targetContractAddress,
413
477
  selector: functionSelector,
414
- to: targetContractAddress
415
- };
416
- const entryPointArtifact = await this.contractDataProvider.getFunctionArtifactWithDebugMetadata(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);
417
488
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
418
489
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
419
490
  }
@@ -422,9 +493,25 @@ export class TXEOracleTopLevelContext {
422
493
  selector: call.selector
423
494
  });
424
495
  try {
425
- const anchorBlockHeader = await this.stateMachine.anchorBlockDataProvider.getBlockHeader();
426
- const oracle = new UtilityExecutionOracle(call.to, [], [], anchorBlockHeader, this.contractDataProvider, this.noteDataProvider, this.keyStore, this.addressDataProvider, this.stateMachine.node, this.stateMachine.anchorBlockDataProvider, this.senderTaggingDataProvider, this.recipientTaggingDataProvider, this.capsuleDataProvider, this.privateEventDataProvider);
427
- 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)=>{
428
515
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
429
516
  throw new ExecutionError(err.message, {
430
517
  contractAddress: call.to,
@@ -433,10 +520,10 @@ export class TXEOracleTopLevelContext {
433
520
  cause: err
434
521
  });
435
522
  });
436
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
523
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
437
524
  return witnessMapToFields(acirExecutionResult.returnWitness);
438
525
  } catch (err) {
439
- 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'));
440
527
  }
441
528
  }
442
529
  close() {