@aztec/txe 0.0.1-commit.96bb3f7 → 0.0.1-commit.993d240

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 (138) hide show
  1. package/dest/ContractClassRegistry-KKNT527R.js +3 -0
  2. package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
  4. package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
  5. package/dest/FeeJuice-GUJ5O6GB.js +3 -0
  6. package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
  8. package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
  9. package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
  10. package/dest/SchnorrAccount-QIXE5DXA.js.map +7 -0
  11. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  12. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  13. package/dest/bin/check_txe_oracle_version.js +32 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/chunk-BJVAAXNA.js +3 -0
  17. package/dest/chunk-BJVAAXNA.js.map +7 -0
  18. package/dest/chunk-DF6RMOC6.js +304 -0
  19. package/dest/chunk-DF6RMOC6.js.map +7 -0
  20. package/dest/chunk-PPJTNNUG.js +265 -0
  21. package/dest/chunk-PPJTNNUG.js.map +7 -0
  22. package/dest/constants.d.ts +3 -2
  23. package/dest/constants.d.ts.map +1 -1
  24. package/dest/constants.js +5 -1
  25. package/dest/dispatcher_pool.d.ts +67 -0
  26. package/dest/dispatcher_pool.d.ts.map +1 -0
  27. package/dest/dispatcher_pool.js +284 -0
  28. package/dest/index.d.ts +188 -7
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +148 -75
  31. package/dest/metafile.json +38147 -0
  32. package/dest/msgpackr_fr_extension.d.ts +2 -0
  33. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  34. package/dest/msgpackr_fr_extension.js +21 -0
  35. package/dest/oracle/interfaces.d.ts +40 -28
  36. package/dest/oracle/interfaces.d.ts.map +1 -1
  37. package/dest/oracle/txe_oracle_public_context.d.ts +18 -13
  38. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  39. package/dest/oracle/txe_oracle_public_context.js +31 -16
  40. package/dest/oracle/txe_oracle_top_level_context.d.ts +39 -23
  41. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  42. package/dest/oracle/txe_oracle_top_level_context.js +225 -89
  43. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  44. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  45. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  46. package/dest/rpc_server.d.ts +14 -0
  47. package/dest/rpc_server.d.ts.map +1 -0
  48. package/dest/rpc_server.js +78 -0
  49. package/dest/rpc_translator.d.ts +144 -82
  50. package/dest/rpc_translator.d.ts.map +1 -1
  51. package/dest/rpc_translator.js +599 -238
  52. package/dest/server.bundle.js +3 -0
  53. package/dest/server.bundle.js.map +7 -0
  54. package/dest/state_machine/archiver.d.ts +20 -69
  55. package/dest/state_machine/archiver.d.ts.map +1 -1
  56. package/dest/state_machine/archiver.js +47 -187
  57. package/dest/state_machine/dummy_p2p_client.d.ts +26 -16
  58. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  59. package/dest/state_machine/dummy_p2p_client.js +44 -20
  60. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  61. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  62. package/dest/state_machine/global_variable_builder.js +9 -3
  63. package/dest/state_machine/index.d.ts +10 -6
  64. package/dest/state_machine/index.d.ts.map +1 -1
  65. package/dest/state_machine/index.js +55 -14
  66. package/dest/state_machine/mock_epoch_cache.d.ts +25 -8
  67. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  68. package/dest/state_machine/mock_epoch_cache.js +46 -9
  69. package/dest/state_machine/synchronizer.d.ts +6 -6
  70. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  71. package/dest/state_machine/synchronizer.js +4 -4
  72. package/dest/txe_oracle_version.d.ts +17 -0
  73. package/dest/txe_oracle_version.d.ts.map +1 -0
  74. package/dest/txe_oracle_version.js +14 -0
  75. package/dest/txe_session.d.ts +73 -10
  76. package/dest/txe_session.d.ts.map +1 -1
  77. package/dest/txe_session.js +242 -39
  78. package/dest/utils/block_creation.d.ts +4 -4
  79. package/dest/utils/block_creation.d.ts.map +1 -1
  80. package/dest/utils/block_creation.js +18 -4
  81. package/dest/utils/encoding.d.ts +191 -0
  82. package/dest/utils/encoding.d.ts.map +1 -0
  83. package/dest/{util → utils}/encoding.js +7 -2
  84. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  85. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  86. package/dest/utils/tx_effect_creation.d.ts +2 -3
  87. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  88. package/dest/utils/tx_effect_creation.js +3 -6
  89. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  90. package/dest/utils/txe_account_store.d.ts.map +1 -0
  91. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  92. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  93. package/dest/{util → utils}/txe_public_contract_data_source.js +6 -25
  94. package/dest/worker.bundle.js +3 -0
  95. package/dest/worker.bundle.js.map +7 -0
  96. package/dest/worker.d.ts +2 -0
  97. package/dest/worker.d.ts.map +1 -0
  98. package/dest/worker.js +92 -0
  99. package/package.json +38 -22
  100. package/src/bin/check_txe_oracle_version.ts +37 -0
  101. package/src/bin/index.ts +11 -2
  102. package/src/constants.ts +6 -1
  103. package/src/dispatcher_pool.ts +316 -0
  104. package/src/index.ts +166 -80
  105. package/src/msgpackr_fr_extension.ts +23 -0
  106. package/src/oracle/interfaces.ts +48 -34
  107. package/src/oracle/txe_oracle_public_context.ts +46 -18
  108. package/src/oracle/txe_oracle_top_level_context.ts +282 -151
  109. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  110. package/src/rpc_server.ts +87 -0
  111. package/src/rpc_translator.ts +687 -326
  112. package/src/state_machine/archiver.ts +53 -235
  113. package/src/state_machine/dummy_p2p_client.ts +70 -32
  114. package/src/state_machine/global_variable_builder.ts +18 -3
  115. package/src/state_machine/index.ts +72 -15
  116. package/src/state_machine/mock_epoch_cache.ts +57 -14
  117. package/src/state_machine/synchronizer.ts +6 -6
  118. package/src/txe_oracle_version.ts +17 -0
  119. package/src/txe_session.ts +352 -104
  120. package/src/utils/block_creation.ts +19 -16
  121. package/src/{util → utils}/encoding.ts +8 -2
  122. package/src/utils/tx_effect_creation.ts +3 -11
  123. package/src/{util → utils}/txe_public_contract_data_source.ts +10 -38
  124. package/src/worker.ts +98 -0
  125. package/dest/util/encoding.d.ts +0 -720
  126. package/dest/util/encoding.d.ts.map +0 -1
  127. package/dest/util/expected_failure_error.d.ts.map +0 -1
  128. package/dest/util/txe_account_store.d.ts.map +0 -1
  129. package/dest/util/txe_contract_store.d.ts +0 -12
  130. package/dest/util/txe_contract_store.d.ts.map +0 -1
  131. package/dest/util/txe_contract_store.js +0 -22
  132. package/dest/util/txe_public_contract_data_source.d.ts +0 -21
  133. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  134. package/src/util/txe_contract_store.ts +0 -36
  135. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  136. /package/dest/{util → utils}/txe_account_store.js +0 -0
  137. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  138. /package/src/{util → utils}/txe_account_store.ts +0 -0
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
3
- DEFAULT_DA_GAS_LIMIT,
4
- DEFAULT_L2_GAS_LIMIT,
5
- DEFAULT_TEARDOWN_DA_GAS_LIMIT,
6
- DEFAULT_TEARDOWN_L2_GAS_LIMIT,
3
+ MAX_PRIVATE_LOGS_PER_TX,
7
4
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
8
5
  } from '@aztec/constants';
9
6
  import { BlockNumber } from '@aztec/foundation/branded-types';
@@ -14,13 +11,17 @@ import { TestDateProvider } from '@aztec/foundation/timer';
14
11
  import type { KeyStore } from '@aztec/key-store';
15
12
  import {
16
13
  AddressStore,
14
+ CapsuleService,
17
15
  CapsuleStore,
16
+ type ContractStore,
17
+ type ExecutionHooks,
18
18
  NoteStore,
19
- ORACLE_VERSION,
19
+ ORACLE_VERSION_MAJOR,
20
20
  PrivateEventStore,
21
21
  RecipientTaggingStore,
22
22
  SenderAddressBookStore,
23
23
  SenderTaggingStore,
24
+ composeHooks,
24
25
  enrichPublicSimulationError,
25
26
  } from '@aztec/pxe/server';
26
27
  import {
@@ -62,6 +63,7 @@ import {
62
63
  PrivateToPublicAccumulatedData,
63
64
  PublicCallRequest,
64
65
  } from '@aztec/stdlib/kernel';
66
+ import { hashPublicKey } from '@aztec/stdlib/keys';
65
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
66
68
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
67
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -78,14 +80,13 @@ import {
78
80
  collectNested,
79
81
  } from '@aztec/stdlib/tx';
80
82
  import type { UInt64 } from '@aztec/stdlib/types';
81
- import { ForkCheckpoint } from '@aztec/world-state';
83
+ import { ForkCheckpoint } from '@aztec/world-state/native';
82
84
 
83
- import { DEFAULT_ADDRESS, TXE_JOB_ID } from '../constants.js';
85
+ import { DEFAULT_ADDRESS } from '../constants.js';
84
86
  import type { TXEStateMachine } from '../state_machine/index.js';
85
- import type { TXEAccountStore } from '../util/txe_account_store.js';
86
- import type { TXEContractStore } from '../util/txe_contract_store.js';
87
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
88
87
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
88
+ import type { TXEAccountStore } from '../utils/txe_account_store.js';
89
+ import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
89
90
  import type { ITxeExecutionOracle } from './interfaces.js';
90
91
 
91
92
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -96,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
96
97
 
97
98
  constructor(
98
99
  private stateMachine: TXEStateMachine,
99
- private contractStore: TXEContractStore,
100
+ private contractStore: ContractStore,
100
101
  private noteStore: NoteStore,
101
102
  private keyStore: KeyStore,
102
103
  private addressStore: AddressStore,
@@ -115,48 +116,62 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
115
116
  this.logger.debug('Entering Top Level Context');
116
117
  }
117
118
 
118
- utilityAssertCompatibleOracleVersion(version: number): void {
119
- if (version !== ORACLE_VERSION) {
119
+ private contractOracleVersion: { major: number; minor: number } | undefined;
120
+
121
+ assertCompatibleOracleVersion(major: number, minor: number): void {
122
+ if (major !== ORACLE_VERSION_MAJOR) {
123
+ const hint =
124
+ major > ORACLE_VERSION_MAJOR
125
+ ? '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.'
126
+ : '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.';
120
127
  throw new Error(
121
- `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
128
+ `Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
122
129
  );
123
130
  }
131
+ this.contractOracleVersion = { major, minor };
132
+ }
133
+
134
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
135
+ nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
136
+ return this.contractOracleVersion;
124
137
  }
125
138
 
126
139
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
127
140
  // setup.
128
- utilityGetRandomField(): Fr {
141
+ getRandomField(): Fr {
129
142
  return Fr.random();
130
143
  }
131
144
 
132
145
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
133
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
146
+ log(level: number, message: string, fields: Fr[]): Promise<void> {
134
147
  if (!LogLevels[level]) {
135
- throw new Error(`Invalid debug log level: ${level}`);
148
+ throw new Error(`Invalid log level: ${level}`);
136
149
  }
137
150
  const levelName = LogLevels[level];
138
151
 
139
152
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
153
+ return Promise.resolve();
140
154
  }
141
155
 
142
- txeGetDefaultAddress(): AztecAddress {
156
+ getDefaultAddress(): AztecAddress {
143
157
  return DEFAULT_ADDRESS;
144
158
  }
145
159
 
146
- async txeGetNextBlockNumber(): Promise<BlockNumber> {
160
+ async getNextBlockNumber(): Promise<BlockNumber> {
147
161
  return BlockNumber((await this.getLastBlockNumber()) + 1);
148
162
  }
149
163
 
150
- txeGetNextBlockTimestamp(): Promise<bigint> {
164
+ getNextBlockTimestamp(): Promise<bigint> {
151
165
  return Promise.resolve(this.nextBlockTimestamp);
152
166
  }
153
167
 
154
- async txeGetLastBlockTimestamp() {
155
- return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
168
+ async getLastBlockTimestamp() {
169
+ return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
156
170
  }
157
171
 
158
- async txeGetLastTxEffects() {
159
- const block = await this.stateMachine.archiver.getL2Block('latest');
172
+ async getLastTxEffects() {
173
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
174
+ const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
160
175
 
161
176
  if (block!.body.txEffects.length != 1) {
162
177
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -165,10 +180,39 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
165
180
 
166
181
  const txEffects = block!.body.txEffects[0];
167
182
 
168
- return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
183
+ const privateLogs = txEffects.privateLogs;
184
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
185
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
186
+ }
187
+
188
+ return {
189
+ txHash: txEffects.txHash,
190
+ noteHashes: txEffects.noteHashes,
191
+ nullifiers: txEffects.nullifiers,
192
+ privateLogs,
193
+ };
169
194
  }
170
195
 
171
- async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
196
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
197
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
198
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
199
+ return;
200
+ }
201
+
202
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
203
+ await this.stateMachine.contractSyncService.ensureContractSynced(
204
+ contractAddress,
205
+ null,
206
+ async (call, execScopes) => {
207
+ await this.executeUtilityCall(call, execScopes, jobId);
208
+ },
209
+ blockHeader,
210
+ jobId,
211
+ [scope],
212
+ );
213
+ }
214
+
215
+ async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
172
216
  return (
173
217
  await this.privateEventStore.getPrivateEvents(selector, {
174
218
  contractAddress,
@@ -179,7 +223,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
179
223
  ).map(e => e.packedEvent);
180
224
  }
181
225
 
182
- async txeAdvanceBlocksBy(blocks: number) {
226
+ async advanceBlocksBy(blocks: number) {
183
227
  this.logger.debug(`time traveling ${blocks} blocks`);
184
228
 
185
229
  for (let i = 0; i < blocks; i++) {
@@ -187,37 +231,45 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
187
231
  }
188
232
  }
189
233
 
190
- txeAdvanceTimestampBy(duration: UInt64) {
234
+ advanceTimestampBy(duration: UInt64) {
191
235
  this.logger.debug(`time traveling ${duration} seconds`);
192
236
  this.nextBlockTimestamp += duration;
193
237
  }
194
238
 
195
- async txeDeploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
239
+ private deploymentNullifier(address: AztecAddress): Promise<Fr> {
240
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
241
+ }
242
+
243
+ async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
196
244
  // Emit deployment nullifier
197
245
  await this.mineBlock({
198
- nullifiers: [
199
- await siloNullifier(
200
- AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
201
- instance.address.toField(),
202
- ),
203
- ],
246
+ nullifiers: [await this.deploymentNullifier(instance.address)],
204
247
  });
205
248
 
206
249
  if (!secret.equals(Fr.ZERO)) {
207
- await this.txeAddAccount(artifact, instance, secret);
250
+ await this.addAccount(artifact, instance, secret);
208
251
  } else {
209
252
  await this.contractStore.addContractInstance(instance);
210
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
253
+ await this.contractStore.addContractArtifact(artifact);
211
254
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
212
255
  }
213
256
  }
214
257
 
215
- async txeAddAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
258
+ /**
259
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
260
+ */
261
+ async mineDeploymentNullifiers(addresses: AztecAddress[]) {
262
+ await this.mineBlock({
263
+ nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
264
+ });
265
+ }
266
+
267
+ async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
216
268
  const partialAddress = await computePartialAddress(instance);
217
269
 
218
270
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
219
271
  await this.contractStore.addContractInstance(instance);
220
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
272
+ await this.contractStore.addContractArtifact(artifact);
221
273
 
222
274
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
223
275
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -227,7 +279,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
227
279
  return completeAddress;
228
280
  }
229
281
 
230
- async txeCreateAccount(secret: Fr) {
282
+ async createAccount(secret: Fr) {
231
283
  // This is a foot gun !
232
284
  const completeAddress = await this.keyStore.addAccount(secret, secret);
233
285
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -237,20 +289,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
237
289
  return completeAddress;
238
290
  }
239
291
 
240
- async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
292
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
241
293
  const account = await this.accountStore.getAccount(address);
242
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
294
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
295
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
243
296
 
244
297
  const schnorr = new Schnorr();
245
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
298
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
246
299
 
247
- const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
300
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
248
301
 
249
302
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
250
303
  }
251
304
 
252
305
  async mineBlock(options: { nullifiers?: Fr[] } = {}) {
253
- const blockNumber = await this.txeGetNextBlockNumber();
306
+ const blockNumber = await this.getNextBlockNumber();
254
307
 
255
308
  const txEffect = TxEffect.empty();
256
309
  txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
@@ -274,13 +327,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
274
327
  await this.stateMachine.handleL2Block(block);
275
328
  }
276
329
 
277
- async txePrivateCallNewFlow(
278
- from: AztecAddress,
330
+ async privateCallNewFlow(
331
+ from: AztecAddress | undefined,
279
332
  targetContractAddress: AztecAddress = AztecAddress.zero(),
280
333
  functionSelector: FunctionSelector = FunctionSelector.empty(),
281
334
  args: Fr[],
282
335
  argsHash: Fr = Fr.zero(),
283
336
  isStaticCall: boolean = false,
337
+ additionalScopes: AztecAddress[] = [],
338
+ jobId: string,
339
+ authorizedUtilityCallTargets: AztecAddress[],
340
+ gasSettings: GasSettings,
284
341
  ) {
285
342
  this.logger.verbose(
286
343
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -294,68 +351,80 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
294
351
  throw new Error(message);
295
352
  }
296
353
 
354
+ const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
355
+
297
356
  // Sync notes before executing private function to discover notes from previous transactions
298
- const utilityExecutor = async (call: FunctionCall) => {
299
- await this.executeUtilityCall(call);
357
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
358
+ await this.executeUtilityCall(call, execScopes, jobId);
300
359
  };
301
360
 
302
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
303
-
304
- const blockNumber = await this.txeGetNextBlockNumber();
361
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
362
+ await this.stateMachine.contractSyncService.ensureContractSynced(
363
+ targetContractAddress,
364
+ functionSelector,
365
+ utilityExecutor,
366
+ blockHeader,
367
+ jobId,
368
+ scopes,
369
+ );
305
370
 
306
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
371
+ const blockNumber = await this.getNextBlockNumber();
307
372
 
308
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
309
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
310
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
373
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
374
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
311
375
 
312
376
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
313
377
 
314
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
315
-
316
378
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
317
379
  const noteCache = new ExecutionNoteCache(protocolNullifier);
380
+ // In production, the account contract sets the min revertible counter before calling the app function.
381
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
382
+ // marking all side effects as revertible.
383
+ const minRevertibleSideEffectCounter = 1;
384
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
318
385
  const taggingIndexCache = new ExecutionTaggingIndexCache();
319
386
 
320
387
  const simulator = new WASMSimulator();
321
388
 
322
- const privateExecutionOracle = new PrivateExecutionOracle(
389
+ const privateExecutionOracle = new PrivateExecutionOracle({
323
390
  argsHash,
324
391
  txContext,
325
392
  callContext,
326
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
327
- blockHeader,
393
+ anchorBlockHeader: blockHeader,
328
394
  utilityExecutor,
329
- /** List of transient auth witnesses to be used during this simulation */
330
- Array.from(this.authwits.values()),
331
- /** List of transient auth witnesses to be used during this simulation */
332
- [],
333
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
395
+ authWitnesses: Array.from(this.authwits.values()),
396
+ capsules: [],
397
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
334
398
  noteCache,
335
399
  taggingIndexCache,
336
- this.contractStore,
337
- this.noteStore,
338
- this.keyStore,
339
- this.addressStore,
340
- this.stateMachine.node,
341
- this.stateMachine.anchorBlockStore,
342
- this.senderTaggingStore,
343
- this.recipientTaggingStore,
344
- this.senderAddressBookStore,
345
- this.capsuleStore,
346
- this.privateEventStore,
347
- TXE_JOB_ID,
348
- 0,
349
- 1,
350
- undefined, // log
351
- undefined, // scopes
352
- /**
353
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
354
- * contract would perform, including setting senderForTags.
355
- */
356
- from,
400
+ contractStore: this.contractStore,
401
+ noteStore: this.noteStore,
402
+ keyStore: this.keyStore,
403
+ addressStore: this.addressStore,
404
+ aztecNode: this.stateMachine.node,
405
+ senderTaggingStore: this.senderTaggingStore,
406
+ recipientTaggingStore: this.recipientTaggingStore,
407
+ senderAddressBookStore: this.senderAddressBookStore,
408
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
409
+ privateEventStore: this.privateEventStore,
410
+ contractSyncService: this.stateMachine.contractSyncService,
411
+ jobId,
412
+ totalPublicCalldataCount: 0,
413
+ sideEffectCounter: minRevertibleSideEffectCounter,
414
+ scopes,
415
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
416
+ // contract would perform, including setting senderForTags.
417
+ senderForTags: from,
357
418
  simulator,
358
- );
419
+ messageContextService: this.stateMachine.messageContextService,
420
+ l2TipsStore: this.stateMachine.l2TipsProvider,
421
+ hooks: composeHooks({
422
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
423
+ isStaticCall ? 'private view' : 'private',
424
+ authorizedUtilityCallTargets,
425
+ ),
426
+ }),
427
+ });
359
428
 
360
429
  // 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.
361
430
  let result: PrivateExecutionResult;
@@ -377,24 +446,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
377
446
  );
378
447
  const publicFunctionsCalldata = await Promise.all(
379
448
  publicCallRequests.map(async r => {
380
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
449
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
381
450
  return new HashedValues(calldata, r.calldataHash);
382
451
  }),
383
452
  );
384
453
 
385
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
386
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
387
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
388
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
454
+ noteCache.finish();
455
+ const nonceGenerator = noteCache.getNonceGenerator();
456
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
389
457
  } catch (err) {
390
458
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
391
459
  }
392
460
 
393
- // According to the protocol rules, the nonce generator for the note hashes
394
- // can either be the first nullifier in the tx or the hash of the initial tx request
395
- // if there are none.
396
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
397
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractStore);
461
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
462
+ // the nonce generator for the note hashes.
463
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
464
+ const { publicInputs } = await generateSimulatedProvingResult(
465
+ result,
466
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
467
+ this.stateMachine.node,
468
+ minRevertibleSideEffectCounter,
469
+ );
398
470
 
399
471
  const globals = makeGlobalVariables();
400
472
  globals.blockNumber = blockNumber;
@@ -405,7 +477,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
405
477
 
406
478
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
407
479
 
408
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
480
+ const bindings = this.logger.getBindings();
481
+ const contractsDB = new PublicContractsDB(
482
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
483
+ bindings,
484
+ );
409
485
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
410
486
  const config = PublicSimulatorConfig.from({
411
487
  skipFeeEnforcement: true,
@@ -418,8 +494,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
418
494
  globals,
419
495
  guardedMerkleTrees,
420
496
  contractsDB,
421
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
497
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
422
498
  new TestDateProvider(),
499
+ undefined,
500
+ createLogger('simulator:public-processor', bindings),
423
501
  );
424
502
 
425
503
  const tx = await Tx.create({
@@ -453,11 +531,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
453
531
  }
454
532
  }
455
533
 
534
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
535
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
536
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
537
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
538
+ const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
539
+
456
540
  if (isStaticCall) {
457
541
  await checkpoint!.revert();
458
542
 
459
543
  await forkedWorldTrees.close();
460
- return executionResult.returnValues ?? [];
544
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
461
545
  }
462
546
 
463
547
  const txEffect = TxEffect.empty();
@@ -479,26 +563,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
479
563
 
480
564
  await forkedWorldTrees.close();
481
565
 
482
- return executionResult.returnValues ?? [];
566
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
483
567
  }
484
568
 
485
- async txePublicCallNewFlow(
486
- from: AztecAddress,
569
+ async publicCallNewFlow(
570
+ from: AztecAddress | undefined,
487
571
  targetContractAddress: AztecAddress,
488
572
  calldata: Fr[],
489
573
  isStaticCall: boolean,
574
+ gasSettings: GasSettings,
490
575
  ) {
491
576
  this.logger.verbose(
492
577
  `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
493
578
  );
494
579
 
495
- const blockNumber = await this.txeGetNextBlockNumber();
496
-
497
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
498
-
499
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
500
-
501
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
580
+ const blockNumber = await this.getNextBlockNumber();
502
581
 
503
582
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
504
583
 
@@ -516,7 +595,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
516
595
 
517
596
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
518
597
 
519
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
598
+ const bindings2 = this.logger.getBindings();
599
+ const contractsDB = new PublicContractsDB(
600
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
601
+ bindings2,
602
+ );
520
603
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
521
604
  const config = PublicSimulatorConfig.from({
522
605
  skipFeeEnforcement: true,
@@ -525,8 +608,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
525
608
  collectStatistics: false,
526
609
  collectCallMetadata: true,
527
610
  });
528
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
529
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
611
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
612
+ const processor = new PublicProcessor(
613
+ globals,
614
+ guardedMerkleTrees,
615
+ contractsDB,
616
+ simulator,
617
+ new TestDateProvider(),
618
+ undefined,
619
+ createLogger('simulator:public-processor', bindings2),
620
+ );
530
621
 
531
622
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
532
623
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -539,7 +630,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
539
630
  // may require producing reverts.
540
631
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
541
632
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
542
- from,
633
+ from ?? AztecAddress.NULL_MSG_SENDER,
543
634
  targetContractAddress,
544
635
  isStaticCall,
545
636
  calldataHash,
@@ -557,7 +648,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
557
648
  constantData,
558
649
  /*gasUsed=*/ new Gas(0, 0),
559
650
  /*feePayer=*/ AztecAddress.zero(),
560
- /*includeByTimestamp=*/ 0n,
651
+ /*expirationTimestamp=*/ 0n,
561
652
  inputsForPublic,
562
653
  undefined,
563
654
  );
@@ -625,10 +716,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
625
716
  return returnValues ?? [];
626
717
  }
627
718
 
628
- async txeSimulateUtilityFunction(
719
+ async executeUtilityFunction(
629
720
  targetContractAddress: AztecAddress,
630
721
  functionSelector: FunctionSelector,
631
722
  args: Fr[],
723
+ jobId: string,
724
+ authorizedUtilityCallTargets: AztecAddress[],
632
725
  ) {
633
726
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
634
727
  if (!artifact) {
@@ -636,25 +729,38 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
636
729
  }
637
730
 
638
731
  // Sync notes before executing utility function to discover notes from previous transactions
639
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async call => {
640
- await this.executeUtilityCall(call);
641
- });
642
-
643
- const call = new FunctionCall(
644
- artifact.name,
732
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
733
+ await this.stateMachine.contractSyncService.ensureContractSynced(
645
734
  targetContractAddress,
646
735
  functionSelector,
647
- FunctionType.UTILITY,
648
- false,
649
- false,
650
- args,
651
- [],
736
+ async (call, execScopes) => {
737
+ await this.executeUtilityCall(call, execScopes, jobId);
738
+ },
739
+ blockHeader,
740
+ jobId,
741
+ await this.keyStore.getAccounts(),
652
742
  );
653
743
 
654
- return this.executeUtilityCall(call);
744
+ const call = FunctionCall.from({
745
+ name: artifact.name,
746
+ to: targetContractAddress,
747
+ selector: functionSelector,
748
+ type: FunctionType.UTILITY,
749
+ hideMsgSender: false,
750
+ isStatic: false,
751
+ args,
752
+ returnTypes: [],
753
+ });
754
+
755
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
655
756
  }
656
757
 
657
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
758
+ private async executeUtilityCall(
759
+ call: FunctionCall,
760
+ scopes: AztecAddress[],
761
+ jobId: string,
762
+ authorizedUtilityCallTargets: AztecAddress[] = [],
763
+ ): Promise<Fr[]> {
658
764
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
659
765
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
660
766
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -667,24 +773,36 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
667
773
 
668
774
  try {
669
775
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
670
- const oracle = new UtilityExecutionOracle(
671
- call.to,
672
- [],
673
- [],
776
+ const simulator = new WASMSimulator();
777
+ const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
778
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
779
+ };
780
+ const oracle = new UtilityExecutionOracle({
781
+ contractAddress: call.to,
782
+ authWitnesses: [],
783
+ capsules: [],
674
784
  anchorBlockHeader,
675
- this.contractStore,
676
- this.noteStore,
677
- this.keyStore,
678
- this.addressStore,
679
- this.stateMachine.node,
680
- this.stateMachine.anchorBlockStore,
681
- this.recipientTaggingStore,
682
- this.senderAddressBookStore,
683
- this.capsuleStore,
684
- this.privateEventStore,
685
- TXE_JOB_ID,
686
- );
687
- const acirExecutionResult = await new WASMSimulator()
785
+ contractStore: this.contractStore,
786
+ noteStore: this.noteStore,
787
+ keyStore: this.keyStore,
788
+ addressStore: this.addressStore,
789
+ aztecNode: this.stateMachine.node,
790
+ recipientTaggingStore: this.recipientTaggingStore,
791
+ senderAddressBookStore: this.senderAddressBookStore,
792
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
793
+ privateEventStore: this.privateEventStore,
794
+ messageContextService: this.stateMachine.messageContextService,
795
+ contractSyncService: this.stateMachine.contractSyncService,
796
+ l2TipsStore: this.stateMachine.l2TipsProvider,
797
+ jobId,
798
+ scopes,
799
+ simulator,
800
+ hooks: composeHooks({
801
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
802
+ }),
803
+ utilityExecutor,
804
+ });
805
+ const acirExecutionResult = await simulator
688
806
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
689
807
  .catch((err: Error) => {
690
808
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
@@ -699,10 +817,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
699
817
  );
700
818
  });
701
819
 
702
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
820
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
703
821
  return witnessMapToFields(acirExecutionResult.returnWitness);
704
822
  } catch (err) {
705
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
823
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
706
824
  }
707
825
  }
708
826
 
@@ -712,7 +830,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
712
830
  }
713
831
 
714
832
  private async getLastBlockNumber(): Promise<BlockNumber> {
715
- const header = await this.stateMachine.node.getBlockHeader('latest');
716
- return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
833
+ const block = await this.stateMachine.node.getBlock('latest');
834
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
835
+ }
836
+
837
+ private buildAuthorizeUtilityCallHook(
838
+ callerContext: 'private' | 'private view' | 'utility',
839
+ authorizedTargets: AztecAddress[],
840
+ ): ExecutionHooks['authorizeUtilityCall'] | undefined {
841
+ if (authorizedTargets.length === 0) {
842
+ return undefined;
843
+ }
844
+ return req =>
845
+ Promise.resolve({
846
+ authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
847
+ });
717
848
  }
718
849
  }