@aztec/txe 0.0.1-commit.9d2bcf6d → 0.0.1-commit.9d619b6c6

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 (64) hide show
  1. package/dest/index.d.ts +1 -1
  2. package/dest/index.d.ts.map +1 -1
  3. package/dest/index.js +88 -54
  4. package/dest/oracle/interfaces.d.ts +32 -28
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +13 -13
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +12 -12
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +30 -23
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +156 -60
  12. package/dest/rpc_translator.d.ts +129 -83
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +464 -164
  15. package/dest/state_machine/archiver.d.ts +3 -3
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +9 -8
  18. package/dest/state_machine/dummy_p2p_client.d.ts +18 -13
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +33 -18
  21. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  22. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  23. package/dest/state_machine/global_variable_builder.js +9 -3
  24. package/dest/state_machine/index.d.ts +7 -5
  25. package/dest/state_machine/index.d.ts.map +1 -1
  26. package/dest/state_machine/index.js +20 -11
  27. package/dest/state_machine/mock_epoch_cache.d.ts +20 -3
  28. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  29. package/dest/state_machine/mock_epoch_cache.js +39 -2
  30. package/dest/state_machine/synchronizer.d.ts +5 -5
  31. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  32. package/dest/state_machine/synchronizer.js +3 -3
  33. package/dest/txe_session.d.ts +54 -6
  34. package/dest/txe_session.d.ts.map +1 -1
  35. package/dest/txe_session.js +151 -27
  36. package/dest/util/encoding.d.ts +71 -1
  37. package/dest/util/encoding.d.ts.map +1 -1
  38. package/dest/util/encoding.js +4 -0
  39. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  40. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  41. package/dest/util/txe_public_contract_data_source.js +6 -25
  42. package/dest/utils/block_creation.d.ts +1 -1
  43. package/dest/utils/block_creation.d.ts.map +1 -1
  44. package/dest/utils/block_creation.js +3 -1
  45. package/package.json +15 -15
  46. package/src/index.ts +89 -52
  47. package/src/oracle/interfaces.ts +33 -32
  48. package/src/oracle/txe_oracle_public_context.ts +12 -12
  49. package/src/oracle/txe_oracle_top_level_context.ts +162 -117
  50. package/src/rpc_translator.ts +539 -196
  51. package/src/state_machine/archiver.ts +8 -5
  52. package/src/state_machine/dummy_p2p_client.ts +46 -24
  53. package/src/state_machine/global_variable_builder.ts +18 -3
  54. package/src/state_machine/index.ts +32 -10
  55. package/src/state_machine/mock_epoch_cache.ts +51 -3
  56. package/src/state_machine/synchronizer.ts +4 -4
  57. package/src/txe_session.ts +216 -75
  58. package/src/util/encoding.ts +5 -0
  59. package/src/util/txe_public_contract_data_source.ts +10 -38
  60. package/src/utils/block_creation.ts +3 -1
  61. package/dest/util/txe_contract_store.d.ts +0 -12
  62. package/dest/util/txe_contract_store.d.ts.map +0 -1
  63. package/dest/util/txe_contract_store.js +0 -22
  64. package/src/util/txe_contract_store.ts +0 -36
@@ -1,10 +1,10 @@
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';
1
+ import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Schnorr } from '@aztec/foundation/crypto/schnorr';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
6
6
  import { TestDateProvider } from '@aztec/foundation/timer';
7
- import { ORACLE_VERSION, enrichPublicSimulationError, syncState } from '@aztec/pxe/server';
7
+ import { CapsuleService, ORACLE_VERSION_MAJOR, 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';
@@ -13,7 +13,7 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
13
13
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
14
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
15
15
  import { computePartialAddress } from '@aztec/stdlib/contract';
16
- import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
16
+ import { FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT, Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
17
17
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
18
18
  import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
19
19
  import { ChonkProof } from '@aztec/stdlib/proofs';
@@ -36,7 +36,6 @@ export class TXEOracleTopLevelContext {
36
36
  senderAddressBookStore;
37
37
  capsuleStore;
38
38
  privateEventStore;
39
- jobId;
40
39
  nextBlockTimestamp;
41
40
  version;
42
41
  chainId;
@@ -44,7 +43,7 @@ export class TXEOracleTopLevelContext {
44
43
  isMisc;
45
44
  isTxe;
46
45
  logger;
47
- constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, jobId, nextBlockTimestamp, version, chainId, authwits){
46
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits){
48
47
  this.stateMachine = stateMachine;
49
48
  this.contractStore = contractStore;
50
49
  this.noteStore = noteStore;
@@ -56,7 +55,6 @@ export class TXEOracleTopLevelContext {
56
55
  this.senderAddressBookStore = senderAddressBookStore;
57
56
  this.capsuleStore = capsuleStore;
58
57
  this.privateEventStore = privateEventStore;
59
- this.jobId = jobId;
60
58
  this.nextBlockTimestamp = nextBlockTimestamp;
61
59
  this.version = version;
62
60
  this.chainId = chainId;
@@ -66,39 +64,50 @@ export class TXEOracleTopLevelContext {
66
64
  this.logger = createLogger('txe:top_level_context');
67
65
  this.logger.debug('Entering Top Level Context');
68
66
  }
69
- utilityAssertCompatibleOracleVersion(version) {
70
- if (version !== ORACLE_VERSION) {
71
- throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
67
+ contractOracleVersion;
68
+ assertCompatibleOracleVersion(major, minor) {
69
+ if (major !== ORACLE_VERSION_MAJOR) {
70
+ const hint = major > ORACLE_VERSION_MAJOR ? 'The contract was compiled with a newer version of Aztec.nr than this aztec cli version supports. Upgrade your aztec cli version to a compatible version.' : 'The contract was compiled with an older version of Aztec.nr than this aztec cli version supports. Recompile the contract with a compatible version of Aztec.nr.';
71
+ throw new Error(`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`);
72
72
  }
73
+ this.contractOracleVersion = {
74
+ major,
75
+ minor
76
+ };
77
+ }
78
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
79
+ nonOracleFunctionGetContractOracleVersion() {
80
+ return this.contractOracleVersion;
73
81
  }
74
82
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
75
83
  // setup.
76
- utilityGetRandomField() {
84
+ getRandomField() {
77
85
  return Fr.random();
78
86
  }
79
87
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
80
- utilityDebugLog(level, message, fields) {
88
+ log(level, message, fields) {
81
89
  if (!LogLevels[level]) {
82
- throw new Error(`Invalid debug log level: ${level}`);
90
+ throw new Error(`Invalid log level: ${level}`);
83
91
  }
84
92
  const levelName = LogLevels[level];
85
93
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
86
94
  module: `${this.logger.module}:debug_log`
87
95
  });
96
+ return Promise.resolve();
88
97
  }
89
- txeGetDefaultAddress() {
98
+ getDefaultAddress() {
90
99
  return DEFAULT_ADDRESS;
91
100
  }
92
- async txeGetNextBlockNumber() {
101
+ async getNextBlockNumber() {
93
102
  return BlockNumber(await this.getLastBlockNumber() + 1);
94
103
  }
95
- txeGetNextBlockTimestamp() {
104
+ getNextBlockTimestamp() {
96
105
  return Promise.resolve(this.nextBlockTimestamp);
97
106
  }
98
- async txeGetLastBlockTimestamp() {
107
+ async getLastBlockTimestamp() {
99
108
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
100
109
  }
101
- async txeGetLastTxEffects() {
110
+ async getLastTxEffects() {
102
111
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
103
112
  const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
104
113
  if (block.body.txEffects.length != 1) {
@@ -112,7 +121,19 @@ export class TXEOracleTopLevelContext {
112
121
  nullifiers: txEffects.nullifiers
113
122
  };
114
123
  }
115
- async txeGetPrivateEvents(selector, contractAddress, scope) {
124
+ async syncContractNonOracleMethod(contractAddress, scope, jobId) {
125
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
126
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
127
+ return;
128
+ }
129
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
130
+ await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
131
+ await this.executeUtilityCall(call, execScopes, jobId);
132
+ }, blockHeader, jobId, [
133
+ scope
134
+ ]);
135
+ }
136
+ async getPrivateEvents(selector, contractAddress, scope) {
116
137
  return (await this.privateEventStore.getPrivateEvents(selector, {
117
138
  contractAddress,
118
139
  scopes: [
@@ -122,17 +143,17 @@ export class TXEOracleTopLevelContext {
122
143
  toBlock: await this.getLastBlockNumber() + 1
123
144
  })).map((e)=>e.packedEvent);
124
145
  }
125
- async txeAdvanceBlocksBy(blocks) {
146
+ async advanceBlocksBy(blocks) {
126
147
  this.logger.debug(`time traveling ${blocks} blocks`);
127
148
  for(let i = 0; i < blocks; i++){
128
149
  await this.mineBlock();
129
150
  }
130
151
  }
131
- txeAdvanceTimestampBy(duration) {
152
+ advanceTimestampBy(duration) {
132
153
  this.logger.debug(`time traveling ${duration} seconds`);
133
154
  this.nextBlockTimestamp += duration;
134
155
  }
135
- async txeDeploy(artifact, instance, secret) {
156
+ async deploy(artifact, instance, secret) {
136
157
  // Emit deployment nullifier
137
158
  await this.mineBlock({
138
159
  nullifiers: [
@@ -140,25 +161,25 @@ export class TXEOracleTopLevelContext {
140
161
  ]
141
162
  });
142
163
  if (!secret.equals(Fr.ZERO)) {
143
- await this.txeAddAccount(artifact, instance, secret);
164
+ await this.addAccount(artifact, instance, secret);
144
165
  } else {
145
166
  await this.contractStore.addContractInstance(instance);
146
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
167
+ await this.contractStore.addContractArtifact(artifact);
147
168
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
148
169
  }
149
170
  }
150
- async txeAddAccount(artifact, instance, secret) {
171
+ async addAccount(artifact, instance, secret) {
151
172
  const partialAddress = await computePartialAddress(instance);
152
173
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
153
174
  await this.contractStore.addContractInstance(instance);
154
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
175
+ await this.contractStore.addContractArtifact(artifact);
155
176
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
156
177
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
157
178
  await this.addressStore.addCompleteAddress(completeAddress);
158
179
  this.logger.debug(`Created account ${completeAddress.address}`);
159
180
  return completeAddress;
160
181
  }
161
- async txeCreateAccount(secret) {
182
+ async createAccount(secret) {
162
183
  // This is a foot gun !
163
184
  const completeAddress = await this.keyStore.addAccount(secret, secret);
164
185
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -166,7 +187,7 @@ export class TXEOracleTopLevelContext {
166
187
  this.logger.debug(`Created account ${completeAddress.address}`);
167
188
  return completeAddress;
168
189
  }
169
- async txeAddAuthWitness(address, messageHash) {
190
+ async addAuthWitness(address, messageHash) {
170
191
  const account = await this.accountStore.getAccount(address);
171
192
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
172
193
  const schnorr = new Schnorr();
@@ -177,7 +198,7 @@ export class TXEOracleTopLevelContext {
177
198
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
178
199
  }
179
200
  async mineBlock(options = {}) {
180
- const blockNumber = await this.txeGetNextBlockNumber();
201
+ const blockNumber = await this.getNextBlockNumber();
181
202
  const txEffect = TxEffect.empty();
182
203
  txEffect.nullifiers = [
183
204
  getSingleTxBlockRequestHash(blockNumber),
@@ -199,23 +220,28 @@ export class TXEOracleTopLevelContext {
199
220
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
200
221
  await this.stateMachine.handleL2Block(block);
201
222
  }
202
- async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
223
+ async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
203
224
  this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
204
225
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
205
226
  if (!artifact) {
206
227
  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';
207
228
  throw new Error(message);
208
229
  }
230
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
231
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
232
+ const effectiveScopes = from.isZero() ? [] : [
233
+ from
234
+ ];
209
235
  // Sync notes before executing private function to discover notes from previous transactions
210
- const utilityExecutor = async (call)=>{
211
- await this.executeUtilityCall(call);
236
+ const utilityExecutor = async (call, execScopes)=>{
237
+ await this.executeUtilityCall(call, execScopes, jobId);
212
238
  };
213
239
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
214
- await syncState(targetContractAddress, this.contractStore, functionSelector, utilityExecutor, this.noteStore, this.stateMachine.node, blockHeader, this.jobId);
215
- const blockNumber = await this.txeGetNextBlockNumber();
240
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
241
+ const blockNumber = await this.getNextBlockNumber();
216
242
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
217
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
218
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
243
+ const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
244
+ const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
219
245
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
220
246
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
221
247
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
@@ -227,12 +253,41 @@ export class TXEOracleTopLevelContext {
227
253
  await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
228
254
  const taggingIndexCache = new ExecutionTaggingIndexCache();
229
255
  const simulator = new WASMSimulator();
230
- 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, utilityExecutor, /** 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([
231
- new HashedValues(args, argsHash)
232
- ]), noteCache, taggingIndexCache, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.jobId, 0, minRevertibleSideEffectCounter, undefined, undefined, /**
233
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
234
- * contract would perform, including setting senderForTags.
235
- */ from, simulator);
256
+ const privateExecutionOracle = new PrivateExecutionOracle({
257
+ argsHash,
258
+ txContext,
259
+ callContext,
260
+ anchorBlockHeader: blockHeader,
261
+ utilityExecutor,
262
+ authWitnesses: Array.from(this.authwits.values()),
263
+ capsules: [],
264
+ executionCache: HashedValuesCache.create([
265
+ new HashedValues(args, argsHash)
266
+ ]),
267
+ noteCache,
268
+ taggingIndexCache,
269
+ contractStore: this.contractStore,
270
+ noteStore: this.noteStore,
271
+ keyStore: this.keyStore,
272
+ addressStore: this.addressStore,
273
+ aztecNode: this.stateMachine.node,
274
+ senderTaggingStore: this.senderTaggingStore,
275
+ recipientTaggingStore: this.recipientTaggingStore,
276
+ senderAddressBookStore: this.senderAddressBookStore,
277
+ capsuleService: new CapsuleService(this.capsuleStore, effectiveScopes),
278
+ privateEventStore: this.privateEventStore,
279
+ contractSyncService: this.stateMachine.contractSyncService,
280
+ jobId,
281
+ totalPublicCalldataCount: 0,
282
+ sideEffectCounter: minRevertibleSideEffectCounter,
283
+ scopes: effectiveScopes,
284
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
285
+ // contract would perform, including setting senderForTags.
286
+ senderForTags: from,
287
+ simulator,
288
+ messageContextService: this.stateMachine.messageContextService,
289
+ l2TipsStore: this.stateMachine.node
290
+ });
236
291
  // 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.
237
292
  let result;
238
293
  let executionResult;
@@ -244,7 +299,7 @@ export class TXEOracleTopLevelContext {
244
299
  r.publicInputs.publicTeardownCallRequest
245
300
  ]));
246
301
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
247
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
302
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
248
303
  return new HashedValues(calldata, r.calldataHash);
249
304
  }));
250
305
  noteCache.finish();
@@ -256,7 +311,7 @@ export class TXEOracleTopLevelContext {
256
311
  // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
257
312
  // the nonce generator for the note hashes.
258
313
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
259
- const { publicInputs } = await generateSimulatedProvingResult(result, this.contractStore, minRevertibleSideEffectCounter);
314
+ const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
260
315
  const globals = makeGlobalVariables();
261
316
  globals.blockNumber = blockNumber;
262
317
  globals.timestamp = this.nextBlockTimestamp;
@@ -303,10 +358,20 @@ export class TXEOracleTopLevelContext {
303
358
  throw new Error('Contract execution has reverted');
304
359
  }
305
360
  }
361
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
362
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
363
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
364
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
365
+ const offchainEffects = collectNested([
366
+ executionResult
367
+ ], (r)=>r.offchainEffects.map((e)=>e.data));
306
368
  if (isStaticCall) {
307
369
  await checkpoint.revert();
308
370
  await forkedWorldTrees.close();
309
- return executionResult.returnValues ?? [];
371
+ return {
372
+ returnValues: executionResult.returnValues ?? [],
373
+ offchainEffects
374
+ };
310
375
  }
311
376
  const txEffect = TxEffect.empty();
312
377
  txEffect.noteHashes = processedTx.txEffect.noteHashes;
@@ -322,13 +387,16 @@ export class TXEOracleTopLevelContext {
322
387
  ]);
323
388
  await this.stateMachine.handleL2Block(l2Block);
324
389
  await forkedWorldTrees.close();
325
- return executionResult.returnValues ?? [];
390
+ return {
391
+ returnValues: executionResult.returnValues ?? [],
392
+ offchainEffects
393
+ };
326
394
  }
327
- async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
395
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
328
396
  this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
329
- const blockNumber = await this.txeGetNextBlockNumber();
330
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
331
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
397
+ const blockNumber = await this.getNextBlockNumber();
398
+ const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
399
+ const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
332
400
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
333
401
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
334
402
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -365,7 +433,7 @@ export class TXEOracleTopLevelContext {
365
433
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
366
434
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
367
435
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
368
- const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
436
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
369
437
  const tx = await Tx.create({
370
438
  data: txData,
371
439
  chonkProof: ChonkProof.empty(),
@@ -418,20 +486,29 @@ export class TXEOracleTopLevelContext {
418
486
  await forkedWorldTrees.close();
419
487
  return returnValues ?? [];
420
488
  }
421
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
489
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
422
490
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
423
491
  if (!artifact) {
424
492
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
425
493
  }
426
494
  // Sync notes before executing utility function to discover notes from previous transactions
427
495
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
428
- await syncState(targetContractAddress, this.contractStore, functionSelector, async (call)=>{
429
- await this.executeUtilityCall(call);
430
- }, this.noteStore, this.stateMachine.node, blockHeader, this.jobId);
431
- const call = new FunctionCall(artifact.name, targetContractAddress, functionSelector, FunctionType.UTILITY, false, false, args, []);
432
- return this.executeUtilityCall(call);
496
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
497
+ await this.executeUtilityCall(call, execScopes, jobId);
498
+ }, blockHeader, jobId, await this.keyStore.getAccounts());
499
+ const call = FunctionCall.from({
500
+ name: artifact.name,
501
+ to: targetContractAddress,
502
+ selector: functionSelector,
503
+ type: FunctionType.UTILITY,
504
+ hideMsgSender: false,
505
+ isStatic: false,
506
+ args,
507
+ returnTypes: []
508
+ });
509
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId);
433
510
  }
434
- async executeUtilityCall(call) {
511
+ async executeUtilityCall(call, scopes, jobId) {
435
512
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
436
513
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
437
514
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -442,7 +519,26 @@ export class TXEOracleTopLevelContext {
442
519
  });
443
520
  try {
444
521
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
445
- const oracle = new UtilityExecutionOracle(call.to, [], [], anchorBlockHeader, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.jobId);
522
+ const oracle = new UtilityExecutionOracle({
523
+ contractAddress: call.to,
524
+ authWitnesses: [],
525
+ capsules: [],
526
+ anchorBlockHeader,
527
+ contractStore: this.contractStore,
528
+ noteStore: this.noteStore,
529
+ keyStore: this.keyStore,
530
+ addressStore: this.addressStore,
531
+ aztecNode: this.stateMachine.node,
532
+ recipientTaggingStore: this.recipientTaggingStore,
533
+ senderAddressBookStore: this.senderAddressBookStore,
534
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
535
+ privateEventStore: this.privateEventStore,
536
+ messageContextService: this.stateMachine.messageContextService,
537
+ contractSyncService: this.stateMachine.contractSyncService,
538
+ l2TipsStore: this.stateMachine.node,
539
+ jobId,
540
+ scopes
541
+ });
446
542
  const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
447
543
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
448
544
  throw new ExecutionError(err.message, {
@@ -452,10 +548,10 @@ export class TXEOracleTopLevelContext {
452
548
  cause: err
453
549
  });
454
550
  });
455
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
551
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
456
552
  return witnessMapToFields(acirExecutionResult.returnWitness);
457
553
  } catch (err) {
458
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
554
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
459
555
  }
460
556
  }
461
557
  close() {