@aztec/txe 5.0.0-private.20260318 → 5.0.0-rc.1

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 (154) hide show
  1. package/dest/AuthRegistry-CPGFQR26.js +3 -0
  2. package/dest/AuthRegistry-CPGFQR26.js.map +7 -0
  3. package/dest/ContractClassRegistry-EHVIHGEK.js +3 -0
  4. package/dest/ContractClassRegistry-EHVIHGEK.js.map +7 -0
  5. package/dest/ContractInstanceRegistry-DWZDXHRG.js +3 -0
  6. package/dest/ContractInstanceRegistry-DWZDXHRG.js.map +7 -0
  7. package/dest/FeeJuice-MI32ZO7B.js +3 -0
  8. package/dest/FeeJuice-MI32ZO7B.js.map +7 -0
  9. package/dest/HandshakeRegistry-3KSP3ITH.js +3 -0
  10. package/dest/HandshakeRegistry-3KSP3ITH.js.map +7 -0
  11. package/dest/MultiCallEntrypoint-IU7HYFYE.js +3 -0
  12. package/dest/MultiCallEntrypoint-IU7HYFYE.js.map +7 -0
  13. package/dest/SchnorrAccount-6TUE7JX4.js +3 -0
  14. package/dest/SchnorrAccount-6TUE7JX4.js.map +7 -0
  15. package/dest/SchnorrInitializerlessAccount-S3DU2DJK.js +3 -0
  16. package/dest/SchnorrInitializerlessAccount-S3DU2DJK.js.map +7 -0
  17. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  18. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  19. package/dest/bin/check_txe_oracle_version.js +61 -0
  20. package/dest/bin/index.js +3 -30
  21. package/dest/bin/index.js.map +7 -0
  22. package/dest/bin/oracle_test_server.d.ts +3 -0
  23. package/dest/bin/oracle_test_server.d.ts.map +1 -0
  24. package/dest/bin/oracle_test_server.js +41 -0
  25. package/dest/chunk-5U25VAFR.js +265 -0
  26. package/dest/chunk-5U25VAFR.js.map +7 -0
  27. package/dest/chunk-BJVAAXNA.js +3 -0
  28. package/dest/chunk-BJVAAXNA.js.map +7 -0
  29. package/dest/chunk-UPW55EJX.js +304 -0
  30. package/dest/chunk-UPW55EJX.js.map +7 -0
  31. package/dest/constants.d.ts +5 -1
  32. package/dest/constants.d.ts.map +1 -1
  33. package/dest/constants.js +8 -0
  34. package/dest/dispatcher_pool.d.ts +67 -0
  35. package/dest/dispatcher_pool.d.ts.map +1 -0
  36. package/dest/dispatcher_pool.js +286 -0
  37. package/dest/index.d.ts +51 -7
  38. package/dest/index.d.ts.map +1 -1
  39. package/dest/index.js +70 -190
  40. package/dest/metafile.json +38829 -0
  41. package/dest/msgpackr_fr_extension.d.ts +2 -0
  42. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  43. package/dest/msgpackr_fr_extension.js +21 -0
  44. package/dest/oracle/interfaces.d.ts +33 -8
  45. package/dest/oracle/interfaces.d.ts.map +1 -1
  46. package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
  47. package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
  48. package/dest/oracle/test-resolver/fixtures.js +39 -0
  49. package/dest/oracle/test-resolver/index.d.ts +9 -0
  50. package/dest/oracle/test-resolver/index.d.ts.map +1 -0
  51. package/dest/oracle/test-resolver/index.js +33 -0
  52. package/dest/oracle/test-resolver/resolver.d.ts +34 -0
  53. package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
  54. package/dest/oracle/test-resolver/resolver.js +114 -0
  55. package/dest/oracle/txe_oracle_public_context.d.ts +26 -2
  56. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  57. package/dest/oracle/txe_oracle_public_context.js +43 -1
  58. package/dest/oracle/txe_oracle_registry.d.ts +14 -0
  59. package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
  60. package/dest/oracle/txe_oracle_registry.js +562 -0
  61. package/dest/oracle/txe_oracle_top_level_context.d.ts +32 -18
  62. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  63. package/dest/oracle/txe_oracle_top_level_context.js +151 -55
  64. package/dest/oracle/txe_oracle_version.d.ts +17 -0
  65. package/dest/oracle/txe_oracle_version.d.ts.map +1 -0
  66. package/dest/oracle/txe_oracle_version.js +14 -0
  67. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  68. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  69. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  70. package/dest/rpc_server.d.ts +14 -0
  71. package/dest/rpc_server.d.ts.map +1 -0
  72. package/dest/rpc_server.js +78 -0
  73. package/dest/rpc_translator.d.ts +103 -230
  74. package/dest/rpc_translator.d.ts.map +1 -1
  75. package/dest/rpc_translator.js +697 -616
  76. package/dest/server.bundle.js +3 -0
  77. package/dest/server.bundle.js.map +7 -0
  78. package/dest/state_machine/archiver.d.ts +4 -3
  79. package/dest/state_machine/archiver.d.ts.map +1 -1
  80. package/dest/state_machine/archiver.js +26 -15
  81. package/dest/state_machine/dummy_p2p_client.d.ts +14 -7
  82. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  83. package/dest/state_machine/dummy_p2p_client.js +19 -4
  84. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  85. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  86. package/dest/state_machine/global_variable_builder.js +9 -3
  87. package/dest/state_machine/index.d.ts +4 -2
  88. package/dest/state_machine/index.d.ts.map +1 -1
  89. package/dest/state_machine/index.js +11 -3
  90. package/dest/state_machine/mock_epoch_cache.d.ts +16 -3
  91. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  92. package/dest/state_machine/mock_epoch_cache.js +29 -2
  93. package/dest/state_machine/synchronizer.js +1 -1
  94. package/dest/txe_session.d.ts +85 -17
  95. package/dest/txe_session.d.ts.map +1 -1
  96. package/dest/txe_session.js +245 -40
  97. package/dest/utils/encoding.d.ts +191 -0
  98. package/dest/utils/encoding.d.ts.map +1 -0
  99. package/dest/{util → utils}/encoding.js +7 -2
  100. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  101. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  102. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  103. package/dest/utils/txe_account_store.d.ts.map +1 -0
  104. package/dest/utils/txe_artifact_resolver.d.ts +37 -0
  105. package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
  106. package/dest/utils/txe_artifact_resolver.js +161 -0
  107. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  108. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  109. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  110. package/dest/worker.bundle.js +3 -0
  111. package/dest/worker.bundle.js.map +7 -0
  112. package/dest/worker.d.ts +2 -0
  113. package/dest/worker.d.ts.map +1 -0
  114. package/dest/worker.js +92 -0
  115. package/package.json +38 -21
  116. package/src/bin/check_txe_oracle_version.ts +70 -0
  117. package/src/bin/index.ts +11 -2
  118. package/src/bin/oracle_test_server.ts +51 -0
  119. package/src/constants.ts +10 -0
  120. package/src/dispatcher_pool.ts +317 -0
  121. package/src/index.ts +97 -227
  122. package/src/msgpackr_fr_extension.ts +23 -0
  123. package/src/oracle/interfaces.ts +29 -7
  124. package/src/oracle/test-resolver/fixtures.ts +84 -0
  125. package/src/oracle/test-resolver/index.ts +45 -0
  126. package/src/oracle/test-resolver/resolver.ts +165 -0
  127. package/src/oracle/txe_oracle_public_context.ts +60 -0
  128. package/src/oracle/txe_oracle_registry.ts +401 -0
  129. package/src/oracle/txe_oracle_top_level_context.ts +185 -64
  130. package/src/oracle/txe_oracle_version.ts +17 -0
  131. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  132. package/src/rpc_server.ts +87 -0
  133. package/src/rpc_translator.ts +767 -892
  134. package/src/state_machine/archiver.ts +38 -16
  135. package/src/state_machine/dummy_p2p_client.ts +35 -11
  136. package/src/state_machine/global_variable_builder.ts +18 -3
  137. package/src/state_machine/index.ts +17 -5
  138. package/src/state_machine/mock_epoch_cache.ts +38 -3
  139. package/src/state_machine/synchronizer.ts +1 -1
  140. package/src/txe_session.ts +437 -50
  141. package/src/{util → utils}/encoding.ts +8 -2
  142. package/src/utils/txe_artifact_resolver.ts +217 -0
  143. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  144. package/src/worker.ts +98 -0
  145. package/dest/util/encoding.d.ts +0 -720
  146. package/dest/util/encoding.d.ts.map +0 -1
  147. package/dest/util/expected_failure_error.d.ts.map +0 -1
  148. package/dest/util/txe_account_store.d.ts.map +0 -1
  149. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  150. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  151. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  152. /package/dest/{util → utils}/txe_account_store.js +0 -0
  153. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  154. /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';
@@ -12,17 +9,19 @@ import { Fr } from '@aztec/foundation/curves/bn254';
12
9
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
13
10
  import { TestDateProvider } from '@aztec/foundation/timer';
14
11
  import type { KeyStore } from '@aztec/key-store';
15
- import type { AccessScopes } from '@aztec/pxe/client/lazy';
16
12
  import {
17
13
  AddressStore,
14
+ CapsuleService,
18
15
  CapsuleStore,
19
16
  type ContractStore,
17
+ type ExecutionHooks,
20
18
  NoteStore,
21
- ORACLE_VERSION,
19
+ ORACLE_VERSION_MAJOR,
22
20
  PrivateEventStore,
23
21
  RecipientTaggingStore,
24
22
  SenderAddressBookStore,
25
23
  SenderTaggingStore,
24
+ composeHooks,
26
25
  enrichPublicSimulationError,
27
26
  } from '@aztec/pxe/server';
28
27
  import {
@@ -30,9 +29,10 @@ import {
30
29
  ExecutionTaggingIndexCache,
31
30
  HashedValuesCache,
32
31
  type IMiscOracle,
33
- Oracle,
34
32
  PrivateExecutionOracle,
33
+ TransientArrayService,
35
34
  UtilityExecutionOracle,
35
+ buildACIRCallback,
36
36
  executePrivateFunction,
37
37
  generateSimulatedProvingResult,
38
38
  } from '@aztec/pxe/simulator';
@@ -64,6 +64,7 @@ import {
64
64
  PrivateToPublicAccumulatedData,
65
65
  PublicCallRequest,
66
66
  } from '@aztec/stdlib/kernel';
67
+ import { hashPublicKey } from '@aztec/stdlib/keys';
67
68
  import { ChonkProof } from '@aztec/stdlib/proofs';
68
69
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
69
70
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -80,13 +81,14 @@ import {
80
81
  collectNested,
81
82
  } from '@aztec/stdlib/tx';
82
83
  import type { UInt64 } from '@aztec/stdlib/types';
83
- import { ForkCheckpoint } from '@aztec/world-state';
84
+ import { ForkCheckpoint } from '@aztec/world-state/native';
84
85
 
85
- import { DEFAULT_ADDRESS } from '../constants.js';
86
+ import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
86
87
  import type { TXEStateMachine } from '../state_machine/index.js';
87
- import type { TXEAccountStore } from '../util/txe_account_store.js';
88
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
89
88
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
89
+ import type { TXEAccountStore } from '../utils/txe_account_store.js';
90
+ import type { TXEArtifactResolver } from '../utils/txe_artifact_resolver.js';
91
+ import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
90
92
  import type { ITxeExecutionOracle } from './interfaces.js';
91
93
 
92
94
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -111,17 +113,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
111
113
  private version: Fr,
112
114
  private chainId: Fr,
113
115
  private authwits: Map<string, AuthWitness>,
116
+ private readonly artifactResolver: TXEArtifactResolver,
117
+ private readonly rootPath: string,
118
+ private readonly packageName: string,
114
119
  ) {
115
120
  this.logger = createLogger('txe:top_level_context');
116
121
  this.logger.debug('Entering Top Level Context');
117
122
  }
118
123
 
119
- assertCompatibleOracleVersion(version: number): void {
120
- if (version !== ORACLE_VERSION) {
124
+ private contractOracleVersion: { major: number; minor: number } | undefined;
125
+
126
+ assertCompatibleOracleVersion(major: number, minor: number): void {
127
+ if (major !== ORACLE_VERSION_MAJOR) {
128
+ const hint =
129
+ major > ORACLE_VERSION_MAJOR
130
+ ? '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.'
131
+ : '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.';
121
132
  throw new Error(
122
- `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
133
+ `Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
123
134
  );
124
135
  }
136
+ this.contractOracleVersion = { major, minor };
137
+ }
138
+
139
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
140
+ nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
141
+ return this.contractOracleVersion;
125
142
  }
126
143
 
127
144
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
@@ -131,7 +148,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
131
148
  }
132
149
 
133
150
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
134
- log(level: number, message: string, fields: Fr[]): Promise<void> {
151
+ log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
135
152
  if (!LogLevels[level]) {
136
153
  throw new Error(`Invalid log level: ${level}`);
137
154
  }
@@ -154,12 +171,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
154
171
  }
155
172
 
156
173
  async getLastBlockTimestamp() {
157
- return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
174
+ return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
158
175
  }
159
176
 
160
- async getLastTxEffects() {
177
+ async getLastTxEffects(): ReturnType<ITxeExecutionOracle['getLastTxEffects']> {
161
178
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
162
- const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
179
+ const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
163
180
 
164
181
  if (block!.body.txEffects.length != 1) {
165
182
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -168,7 +185,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
168
185
 
169
186
  const txEffects = block!.body.txEffects[0];
170
187
 
171
- return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
188
+ const privateLogs = txEffects.privateLogs;
189
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
190
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
191
+ }
192
+
193
+ return {
194
+ txHash: txEffects.txHash,
195
+ noteHashes: txEffects.noteHashes,
196
+ nullifiers: txEffects.nullifiers,
197
+ privateLogs,
198
+ };
172
199
  }
173
200
 
174
201
  async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
@@ -191,7 +218,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
191
218
  }
192
219
 
193
220
  async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
194
- return (
221
+ const events = (
195
222
  await this.privateEventStore.getPrivateEvents(selector, {
196
223
  contractAddress,
197
224
  scopes: [scope],
@@ -199,6 +226,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
199
226
  toBlock: (await this.getLastBlockNumber()) + 1,
200
227
  })
201
228
  ).map(e => e.packedEvent);
229
+
230
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
231
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
232
+ }
233
+ if (events.some(e => e.length > MAX_PRIVATE_EVENT_LEN)) {
234
+ throw new Error(`Some private event has length larger than maxLen ${MAX_PRIVATE_EVENT_LEN}`);
235
+ }
236
+
237
+ return events;
202
238
  }
203
239
 
204
240
  async advanceBlocksBy(blocks: number) {
@@ -214,27 +250,71 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
214
250
  this.nextBlockTimestamp += duration;
215
251
  }
216
252
 
217
- async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
253
+ private deploymentNullifier(address: AztecAddress): Promise<Fr> {
254
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
255
+ }
256
+
257
+ async deploy(
258
+ contractPath: string,
259
+ initializer: string,
260
+ args: Fr[],
261
+ secret: Fr,
262
+ salt: Fr,
263
+ deployer: AztecAddress,
264
+ ): Promise<Fr[]> {
265
+ const { artifact, instance } = await this.artifactResolver.resolveDeployArtifact({
266
+ rootPath: this.rootPath,
267
+ packageName: this.packageName,
268
+ contractPath,
269
+ initializer,
270
+ args,
271
+ secret,
272
+ salt,
273
+ deployer,
274
+ });
275
+
218
276
  // Emit deployment nullifier
219
277
  await this.mineBlock({
220
- nullifiers: [
221
- await siloNullifier(
222
- AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
223
- instance.address.toField(),
224
- ),
225
- ],
278
+ nullifiers: [await this.deploymentNullifier(instance.address)],
226
279
  });
227
280
 
228
281
  if (!secret.equals(Fr.ZERO)) {
229
- await this.addAccount(artifact, instance, secret);
282
+ await this.registerContractAndAddAccount(artifact, instance, secret);
230
283
  } else {
231
284
  await this.contractStore.addContractInstance(instance);
232
285
  await this.contractStore.addContractArtifact(artifact);
233
286
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
234
287
  }
288
+
289
+ return [
290
+ instance.salt,
291
+ instance.deployer.toField(),
292
+ instance.currentContractClassId,
293
+ instance.initializationHash,
294
+ instance.immutablesHash,
295
+ ...instance.publicKeys.toFields(),
296
+ ];
297
+ }
298
+
299
+ /**
300
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
301
+ */
302
+ async mineDeploymentNullifiers(addresses: AztecAddress[]) {
303
+ await this.mineBlock({
304
+ nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
305
+ });
306
+ }
307
+
308
+ async addAccount(secret: Fr) {
309
+ const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
310
+ return this.registerContractAndAddAccount(artifact, instance, secret);
235
311
  }
236
312
 
237
- async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
313
+ private async registerContractAndAddAccount(
314
+ artifact: ContractArtifact,
315
+ instance: ContractInstanceWithAddress,
316
+ secret: Fr,
317
+ ) {
238
318
  const partialAddress = await computePartialAddress(instance);
239
319
 
240
320
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
@@ -261,12 +341,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
261
341
 
262
342
  async addAuthWitness(address: AztecAddress, messageHash: Fr) {
263
343
  const account = await this.accountStore.getAccount(address);
264
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
344
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
345
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
265
346
 
266
347
  const schnorr = new Schnorr();
267
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
348
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
268
349
 
269
- const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
350
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
270
351
 
271
352
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
272
353
  }
@@ -297,13 +378,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
297
378
  }
298
379
 
299
380
  async privateCallNewFlow(
300
- from: AztecAddress,
381
+ from: AztecAddress | undefined,
301
382
  targetContractAddress: AztecAddress = AztecAddress.zero(),
302
383
  functionSelector: FunctionSelector = FunctionSelector.empty(),
303
384
  args: Fr[],
304
385
  argsHash: Fr = Fr.zero(),
305
386
  isStaticCall: boolean = false,
387
+ additionalScopes: AztecAddress[] = [],
306
388
  jobId: string,
389
+ authorizedUtilityCallTargets: AztecAddress[],
390
+ gasSettings: GasSettings,
307
391
  ) {
308
392
  this.logger.verbose(
309
393
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -317,12 +401,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
317
401
  throw new Error(message);
318
402
  }
319
403
 
320
- // When `from` is the zero address (e.g. when deploying a new account contract), we return an
321
- // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
322
- const effectiveScopes = from.isZero() ? [] : [from];
404
+ const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
323
405
 
324
406
  // Sync notes before executing private function to discover notes from previous transactions
325
- const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
407
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
326
408
  await this.executeUtilityCall(call, execScopes, jobId);
327
409
  };
328
410
 
@@ -333,16 +415,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
333
415
  utilityExecutor,
334
416
  blockHeader,
335
417
  jobId,
336
- effectiveScopes,
418
+ scopes,
337
419
  );
338
420
 
339
421
  const blockNumber = await this.getNextBlockNumber();
340
422
 
341
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
342
-
343
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
344
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
345
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
423
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
424
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
346
425
 
347
426
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
348
427
 
@@ -357,6 +436,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
357
436
 
358
437
  const simulator = new WASMSimulator();
359
438
 
439
+ const transientArrayService = new TransientArrayService();
360
440
  const privateExecutionOracle = new PrivateExecutionOracle({
361
441
  argsHash,
362
442
  txContext,
@@ -376,18 +456,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
376
456
  senderTaggingStore: this.senderTaggingStore,
377
457
  recipientTaggingStore: this.recipientTaggingStore,
378
458
  senderAddressBookStore: this.senderAddressBookStore,
379
- capsuleStore: this.capsuleStore,
459
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
380
460
  privateEventStore: this.privateEventStore,
381
461
  contractSyncService: this.stateMachine.contractSyncService,
382
462
  jobId,
383
463
  totalPublicCalldataCount: 0,
384
464
  sideEffectCounter: minRevertibleSideEffectCounter,
385
- scopes: effectiveScopes,
465
+ scopes,
386
466
  // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
387
467
  // contract would perform, including setting senderForTags.
388
468
  senderForTags: from,
389
469
  simulator,
390
470
  messageContextService: this.stateMachine.messageContextService,
471
+ l2TipsStore: this.stateMachine.l2TipsProvider,
472
+ hooks: composeHooks({
473
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
474
+ isStaticCall ? 'private view' : 'private',
475
+ authorizedUtilityCallTargets,
476
+ ),
477
+ }),
478
+ transientArrayService,
391
479
  });
392
480
 
393
481
  // 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.
@@ -410,7 +498,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
410
498
  );
411
499
  const publicFunctionsCalldata = await Promise.all(
412
500
  publicCallRequests.map(async r => {
413
- const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
501
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
414
502
  return new HashedValues(calldata, r.calldataHash);
415
503
  }),
416
504
  );
@@ -495,11 +583,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
495
583
  }
496
584
  }
497
585
 
586
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
587
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
588
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
589
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
590
+ const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
591
+
498
592
  if (isStaticCall) {
499
593
  await checkpoint!.revert();
500
594
 
501
595
  await forkedWorldTrees.close();
502
- return executionResult.returnValues ?? [];
596
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
503
597
  }
504
598
 
505
599
  const txEffect = TxEffect.empty();
@@ -521,14 +615,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
521
615
 
522
616
  await forkedWorldTrees.close();
523
617
 
524
- return executionResult.returnValues ?? [];
618
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
525
619
  }
526
620
 
527
621
  async publicCallNewFlow(
528
- from: AztecAddress,
622
+ from: AztecAddress | undefined,
529
623
  targetContractAddress: AztecAddress,
530
624
  calldata: Fr[],
531
625
  isStaticCall: boolean,
626
+ gasSettings: GasSettings,
532
627
  ) {
533
628
  this.logger.verbose(
534
629
  `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -536,12 +631,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
536
631
 
537
632
  const blockNumber = await this.getNextBlockNumber();
538
633
 
539
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
540
-
541
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
542
-
543
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
544
-
545
634
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
546
635
 
547
636
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -593,7 +682,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
593
682
  // may require producing reverts.
594
683
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
595
684
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
596
- from,
685
+ from ?? AztecAddress.NULL_MSG_SENDER,
597
686
  targetContractAddress,
598
687
  isStaticCall,
599
688
  calldataHash,
@@ -684,6 +773,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
684
773
  functionSelector: FunctionSelector,
685
774
  args: Fr[],
686
775
  jobId: string,
776
+ authorizedUtilityCallTargets: AztecAddress[],
687
777
  ) {
688
778
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
689
779
  if (!artifact) {
@@ -700,7 +790,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
700
790
  },
701
791
  blockHeader,
702
792
  jobId,
703
- 'ALL_SCOPES',
793
+ await this.keyStore.getAccounts(),
704
794
  );
705
795
 
706
796
  const call = FunctionCall.from({
@@ -714,10 +804,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
714
804
  returnTypes: [],
715
805
  });
716
806
 
717
- return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
807
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
718
808
  }
719
809
 
720
- private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
810
+ private async executeUtilityCall(
811
+ call: FunctionCall,
812
+ scopes: AztecAddress[],
813
+ jobId: string,
814
+ authorizedUtilityCallTargets: AztecAddress[] = [],
815
+ ): Promise<Fr[]> {
721
816
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
722
817
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
723
818
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -730,6 +825,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
730
825
 
731
826
  try {
732
827
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
828
+ const simulator = new WASMSimulator();
829
+ const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
830
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
831
+ };
733
832
  const oracle = new UtilityExecutionOracle({
734
833
  contractAddress: call.to,
735
834
  authWitnesses: [],
@@ -742,14 +841,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
742
841
  aztecNode: this.stateMachine.node,
743
842
  recipientTaggingStore: this.recipientTaggingStore,
744
843
  senderAddressBookStore: this.senderAddressBookStore,
745
- capsuleStore: this.capsuleStore,
844
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
746
845
  privateEventStore: this.privateEventStore,
747
846
  messageContextService: this.stateMachine.messageContextService,
847
+ contractSyncService: this.stateMachine.contractSyncService,
848
+ l2TipsStore: this.stateMachine.l2TipsProvider,
748
849
  jobId,
749
850
  scopes,
851
+ simulator,
852
+ hooks: composeHooks({
853
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
854
+ }),
855
+ utilityExecutor,
856
+ // Execution-tree root (top-level utility run or contract sync): own store; nested frames inherit it.
857
+ transientArrayService: new TransientArrayService(),
750
858
  });
751
- const acirExecutionResult = await new WASMSimulator()
752
- .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
859
+ const acirExecutionResult = await simulator
860
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, buildACIRCallback(oracle))
753
861
  .catch((err: Error) => {
754
862
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
755
863
  throw new ExecutionError(
@@ -776,7 +884,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
776
884
  }
777
885
 
778
886
  private async getLastBlockNumber(): Promise<BlockNumber> {
779
- const header = await this.stateMachine.node.getBlockHeader('latest');
780
- return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
887
+ const block = await this.stateMachine.node.getBlock('latest');
888
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
889
+ }
890
+
891
+ private buildAuthorizeUtilityCallHook(
892
+ callerContext: 'private' | 'private view' | 'utility',
893
+ authorizedTargets: AztecAddress[],
894
+ ): ExecutionHooks['authorizeUtilityCall'] | undefined {
895
+ if (authorizedTargets.length === 0) {
896
+ return undefined;
897
+ }
898
+ return req =>
899
+ Promise.resolve({
900
+ authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
901
+ });
781
902
  }
782
903
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The TXE oracle version constants are used to check that the oracle interface used for tests is in sync between
3
+ * TXE and Aztec.nr. This is separate from the contract oracle version in `pxe/src/oracle_version.ts`, which covers
4
+ * oracles used during contract execution by PXE.
5
+ *
6
+ * The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/test/helpers/txe_oracles.nr`.
7
+ */
8
+ export const TXE_ORACLE_VERSION_MAJOR = 1;
9
+ export const TXE_ORACLE_VERSION_MINOR = 2;
10
+
11
+ /**
12
+ * This hash is computed from the TXE oracle interfaces (IAvmExecutionOracle and ITxeExecutionOracle) and is used to
13
+ * detect when those interfaces change. When it does, bump:
14
+ * - TXE_ORACLE_VERSION_MAJOR (and reset MINOR to 0) for breaking changes, or
15
+ * - TXE_ORACLE_VERSION_MINOR for additive changes (new oracle method added).
16
+ */
17
+ export const TXE_ORACLE_INTERFACE_HASH = '9e5f6ad5fd170d1de5ddd417f19cce47b17382567e08360dc6a783154828e218';
@@ -0,0 +1,30 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { PrivateExecutionOracle } from '@aztec/pxe/simulator';
3
+ import type { FunctionSelector } from '@aztec/stdlib/abi';
4
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
+
6
+ /**
7
+ * TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
8
+ * TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
9
+ */
10
+ export class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
11
+ override callPrivateFunction(
12
+ _targetContractAddress: AztecAddress,
13
+ _functionSelector: FunctionSelector,
14
+ _argsHash: Fr,
15
+ _sideEffectCounter: number,
16
+ _isStaticCall: boolean,
17
+ ): Promise<{ endSideEffectCounter: Fr; returnsHash: Fr }> {
18
+ throw new Error(
19
+ 'Contract calls are forbidden inside a `TestEnvironment::private_context`, use `private_call` instead',
20
+ );
21
+ }
22
+
23
+ override assertValidPublicCalldata(_calldataHash: Fr): Promise<void> {
24
+ throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
25
+ }
26
+
27
+ override notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter: number): Promise<void> {
28
+ throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
29
+ }
30
+ }
@@ -0,0 +1,87 @@
1
+ import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
2
+ import type { Logger } from '@aztec/foundation/log';
3
+
4
+ import type { Socket } from 'node:net';
5
+
6
+ import { TXEDispatcherPool, buildSharedContractStore } from './dispatcher_pool.js';
7
+ import { TXEDispatcher, TXEDispatcherApiSchema } from './index.js';
8
+
9
+ /**
10
+ * Symbol used to tag an incoming TCP socket with the `session_id` it has been associated with.
11
+ * Hidden under a Symbol so we don't risk colliding with anything koa or http core adds.
12
+ */
13
+ const SESSION_SYMBOL = Symbol('txeSessionId');
14
+
15
+ type TaggedSocket = Socket & { [SESSION_SYMBOL]?: number };
16
+
17
+ /**
18
+ * Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
19
+ * worker_threads, no IPC overhead). With any other value oracle calls are
20
+ * routed to a pool of worker threads sized to that value, sticky by `session_id`.
21
+ *
22
+ * Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
23
+ * nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
24
+ * closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
25
+ *
26
+ * Lives in its own module so the worker bundle does not pull in the HTTP server stack.
27
+ */
28
+ export async function createTXERpcServer(logger: Logger) {
29
+ const workerCount = Number(process.env.TXE_WORKERS);
30
+ let dispatcher: TXEDispatcher | TXEDispatcherPool;
31
+ if (workerCount === 1) {
32
+ const { dataDir, schnorrClassId } = await buildSharedContractStore();
33
+ dispatcher = new TXEDispatcher(logger, { contractStoreSourceDir: dataDir, schnorrClassId });
34
+ } else {
35
+ dispatcher = new TXEDispatcherPool(logger, {
36
+ workers: Number.isFinite(workerCount) && workerCount > 1 ? workerCount : undefined,
37
+ });
38
+ }
39
+ const server = createSafeJsonRpcServer(dispatcher, TXEDispatcherApiSchema, {
40
+ http200OnError: true,
41
+ middlewares: [
42
+ async (ctx, next) => {
43
+ // The body parser runs further down the chain, so `ctx.request.body` is populated only
44
+ // after `next()` resolves.
45
+ await next();
46
+ const socket = ctx.req.socket as TaggedSocket;
47
+ if (socket[SESSION_SYMBOL] !== undefined) {
48
+ return;
49
+ }
50
+ const body = (ctx.request as { body?: unknown }).body;
51
+ const sessionId =
52
+ body && typeof body === 'object' && 'params' in body
53
+ ? extractSessionId((body as { params: unknown }).params)
54
+ : undefined;
55
+ if (sessionId === undefined) {
56
+ return;
57
+ }
58
+ socket[SESSION_SYMBOL] = sessionId;
59
+ logger.debug(`Tagged socket with session`, {
60
+ sessionId,
61
+ remoteAddress: socket.remoteAddress,
62
+ remotePort: socket.remotePort,
63
+ });
64
+ socket.once('close', () => {
65
+ logger.debug(`Disposing session on socket close`, { sessionId });
66
+ void dispatcher.disposeSession(sessionId);
67
+ });
68
+ },
69
+ ],
70
+ });
71
+ return server;
72
+ }
73
+
74
+ // Extracts `session_id` from a JSON-RPC `params` array. Always a `number` because session_id
75
+ // comes off `JSON.parse`, which never produces BigInt; values above MAX_SAFE_INTEGER lose
76
+ // precision but still work as a Map key.
77
+ function extractSessionId(params: unknown): number | undefined {
78
+ if (!Array.isArray(params) || params.length === 0) {
79
+ return undefined;
80
+ }
81
+ const first = params[0];
82
+ if (first && typeof first === 'object' && 'session_id' in first) {
83
+ const sid = (first as { session_id: unknown }).session_id;
84
+ return typeof sid === 'number' ? sid : undefined;
85
+ }
86
+ return undefined;
87
+ }