@aztec/txe 0.0.1-commit.d1f2d6c → 0.0.1-commit.d20b825a7

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 +14 -15
  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 +164 -65
  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 +486 -175
  15. package/dest/state_machine/archiver.d.ts +4 -4
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +10 -12
  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 +36 -18
  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 +152 -28
  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 +14 -16
  49. package/src/oracle/txe_oracle_top_level_context.ts +196 -116
  50. package/src/rpc_translator.ts +563 -202
  51. package/src/state_machine/archiver.ts +10 -11
  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 +54 -18
  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 +223 -88
  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 } 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,25 +220,30 @@ 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
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
214
- const blockNumber = await this.txeGetNextBlockNumber();
239
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
240
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
241
+ const blockNumber = await this.getNextBlockNumber();
215
242
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
216
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
217
- 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);
218
245
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
219
246
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
220
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
221
247
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
222
248
  const noteCache = new ExecutionNoteCache(protocolNullifier);
223
249
  // In production, the account contract sets the min revertible counter before calling the app function.
@@ -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.stateMachine.anchorBlockStore, 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;
@@ -264,7 +319,8 @@ export class TXEOracleTopLevelContext {
264
319
  globals.version = this.version;
265
320
  globals.gasFees = GasFees.empty();
266
321
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
267
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
322
+ const bindings = this.logger.getBindings();
323
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
268
324
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
269
325
  const config = PublicSimulatorConfig.from({
270
326
  skipFeeEnforcement: true,
@@ -273,7 +329,7 @@ export class TXEOracleTopLevelContext {
273
329
  collectStatistics: false,
274
330
  collectCallMetadata: true
275
331
  });
276
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config), new TestDateProvider());
332
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
277
333
  const tx = await Tx.create({
278
334
  data: publicInputs,
279
335
  chonkProof: ChonkProof.empty(),
@@ -302,10 +358,20 @@ export class TXEOracleTopLevelContext {
302
358
  throw new Error('Contract execution has reverted');
303
359
  }
304
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));
305
368
  if (isStaticCall) {
306
369
  await checkpoint.revert();
307
370
  await forkedWorldTrees.close();
308
- return executionResult.returnValues ?? [];
371
+ return {
372
+ returnValues: executionResult.returnValues ?? [],
373
+ offchainEffects
374
+ };
309
375
  }
310
376
  const txEffect = TxEffect.empty();
311
377
  txEffect.noteHashes = processedTx.txEffect.noteHashes;
@@ -321,13 +387,16 @@ export class TXEOracleTopLevelContext {
321
387
  ]);
322
388
  await this.stateMachine.handleL2Block(l2Block);
323
389
  await forkedWorldTrees.close();
324
- return executionResult.returnValues ?? [];
390
+ return {
391
+ returnValues: executionResult.returnValues ?? [],
392
+ offchainEffects
393
+ };
325
394
  }
326
- async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
395
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
327
396
  this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
328
- const blockNumber = await this.txeGetNextBlockNumber();
329
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
330
- 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);
331
400
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
332
401
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
333
402
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -340,7 +409,8 @@ export class TXEOracleTopLevelContext {
340
409
  globals.version = this.version;
341
410
  globals.gasFees = GasFees.empty();
342
411
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
343
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
412
+ const bindings2 = this.logger.getBindings();
413
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
344
414
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
345
415
  const config = PublicSimulatorConfig.from({
346
416
  skipFeeEnforcement: true,
@@ -349,8 +419,8 @@ export class TXEOracleTopLevelContext {
349
419
  collectStatistics: false,
350
420
  collectCallMetadata: true
351
421
  });
352
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
353
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
422
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
423
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
354
424
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
355
425
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
356
426
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
@@ -363,7 +433,7 @@ export class TXEOracleTopLevelContext {
363
433
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
364
434
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
365
435
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
366
- 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);
367
437
  const tx = await Tx.create({
368
438
  data: txData,
369
439
  chonkProof: ChonkProof.empty(),
@@ -416,19 +486,29 @@ export class TXEOracleTopLevelContext {
416
486
  await forkedWorldTrees.close();
417
487
  return returnValues ?? [];
418
488
  }
419
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
489
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
420
490
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
421
491
  if (!artifact) {
422
492
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
423
493
  }
424
494
  // Sync notes before executing utility function to discover notes from previous transactions
425
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async (call)=>{
426
- await this.executeUtilityCall(call);
495
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
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: []
427
508
  });
428
- const call = new FunctionCall(artifact.name, targetContractAddress, functionSelector, FunctionType.UTILITY, false, false, args, []);
429
- return this.executeUtilityCall(call);
509
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId);
430
510
  }
431
- async executeUtilityCall(call) {
511
+ async executeUtilityCall(call, scopes, jobId) {
432
512
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
433
513
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
434
514
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -439,7 +519,26 @@ export class TXEOracleTopLevelContext {
439
519
  });
440
520
  try {
441
521
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
442
- const oracle = new UtilityExecutionOracle(call.to, [], [], anchorBlockHeader, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.stateMachine.anchorBlockStore, 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
+ });
443
542
  const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
444
543
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
445
544
  throw new ExecutionError(err.message, {
@@ -449,10 +548,10 @@ export class TXEOracleTopLevelContext {
449
548
  cause: err
450
549
  });
451
550
  });
452
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
551
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
453
552
  return witnessMapToFields(acirExecutionResult.returnWitness);
454
553
  } catch (err) {
455
- 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'));
456
555
  }
457
556
  }
458
557
  close() {