@aztec/txe 5.0.0-private.20260319 → 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 +33 -20
  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 -58
  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 -233
  74. package/dest/rpc_translator.d.ts.map +1 -1
  75. package/dest/rpc_translator.js +695 -636
  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 +1 -2
  91. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  92. package/dest/state_machine/mock_epoch_cache.js +0 -3
  93. package/dest/state_machine/synchronizer.js +1 -1
  94. package/dest/txe_session.d.ts +86 -19
  95. package/dest/txe_session.d.ts.map +1 -1
  96. package/dest/txe_session.js +244 -45
  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 -67
  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 +765 -913
  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 +0 -4
  139. package/src/state_machine/synchronizer.ts +1 -1
  140. package/src/txe_session.ts +434 -57
  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,18 +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,
20
- type ContractSyncService,
17
+ type ExecutionHooks,
21
18
  NoteStore,
22
- ORACLE_VERSION,
19
+ ORACLE_VERSION_MAJOR,
23
20
  PrivateEventStore,
24
21
  RecipientTaggingStore,
25
22
  SenderAddressBookStore,
26
23
  SenderTaggingStore,
24
+ composeHooks,
27
25
  enrichPublicSimulationError,
28
26
  } from '@aztec/pxe/server';
29
27
  import {
@@ -31,9 +29,10 @@ import {
31
29
  ExecutionTaggingIndexCache,
32
30
  HashedValuesCache,
33
31
  type IMiscOracle,
34
- Oracle,
35
32
  PrivateExecutionOracle,
33
+ TransientArrayService,
36
34
  UtilityExecutionOracle,
35
+ buildACIRCallback,
37
36
  executePrivateFunction,
38
37
  generateSimulatedProvingResult,
39
38
  } from '@aztec/pxe/simulator';
@@ -65,6 +64,7 @@ import {
65
64
  PrivateToPublicAccumulatedData,
66
65
  PublicCallRequest,
67
66
  } from '@aztec/stdlib/kernel';
67
+ import { hashPublicKey } from '@aztec/stdlib/keys';
68
68
  import { ChonkProof } from '@aztec/stdlib/proofs';
69
69
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
70
70
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -81,13 +81,14 @@ import {
81
81
  collectNested,
82
82
  } from '@aztec/stdlib/tx';
83
83
  import type { UInt64 } from '@aztec/stdlib/types';
84
- import { ForkCheckpoint } from '@aztec/world-state';
84
+ import { ForkCheckpoint } from '@aztec/world-state/native';
85
85
 
86
- import { DEFAULT_ADDRESS } from '../constants.js';
86
+ import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
87
87
  import type { TXEStateMachine } from '../state_machine/index.js';
88
- import type { TXEAccountStore } from '../util/txe_account_store.js';
89
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
90
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';
91
92
  import type { ITxeExecutionOracle } from './interfaces.js';
92
93
 
93
94
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -112,18 +113,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
112
113
  private version: Fr,
113
114
  private chainId: Fr,
114
115
  private authwits: Map<string, AuthWitness>,
115
- private readonly contractSyncService: ContractSyncService,
116
+ private readonly artifactResolver: TXEArtifactResolver,
117
+ private readonly rootPath: string,
118
+ private readonly packageName: string,
116
119
  ) {
117
120
  this.logger = createLogger('txe:top_level_context');
118
121
  this.logger.debug('Entering Top Level Context');
119
122
  }
120
123
 
121
- assertCompatibleOracleVersion(version: number): void {
122
- 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.';
123
132
  throw new Error(
124
- `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})`,
125
134
  );
126
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;
127
142
  }
128
143
 
129
144
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
@@ -133,7 +148,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
133
148
  }
134
149
 
135
150
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
136
- log(level: number, message: string, fields: Fr[]): Promise<void> {
151
+ log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
137
152
  if (!LogLevels[level]) {
138
153
  throw new Error(`Invalid log level: ${level}`);
139
154
  }
@@ -156,12 +171,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
171
  }
157
172
 
158
173
  async getLastBlockTimestamp() {
159
- return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
174
+ return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
160
175
  }
161
176
 
162
- async getLastTxEffects() {
177
+ async getLastTxEffects(): ReturnType<ITxeExecutionOracle['getLastTxEffects']> {
163
178
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
164
- const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
179
+ const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
165
180
 
166
181
  if (block!.body.txEffects.length != 1) {
167
182
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -170,7 +185,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
170
185
 
171
186
  const txEffects = block!.body.txEffects[0];
172
187
 
173
- 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
+ };
174
199
  }
175
200
 
176
201
  async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
@@ -193,7 +218,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
193
218
  }
194
219
 
195
220
  async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
196
- return (
221
+ const events = (
197
222
  await this.privateEventStore.getPrivateEvents(selector, {
198
223
  contractAddress,
199
224
  scopes: [scope],
@@ -201,6 +226,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
201
226
  toBlock: (await this.getLastBlockNumber()) + 1,
202
227
  })
203
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;
204
238
  }
205
239
 
206
240
  async advanceBlocksBy(blocks: number) {
@@ -216,27 +250,71 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
216
250
  this.nextBlockTimestamp += duration;
217
251
  }
218
252
 
219
- 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
+
220
276
  // Emit deployment nullifier
221
277
  await this.mineBlock({
222
- nullifiers: [
223
- await siloNullifier(
224
- AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
225
- instance.address.toField(),
226
- ),
227
- ],
278
+ nullifiers: [await this.deploymentNullifier(instance.address)],
228
279
  });
229
280
 
230
281
  if (!secret.equals(Fr.ZERO)) {
231
- await this.addAccount(artifact, instance, secret);
282
+ await this.registerContractAndAddAccount(artifact, instance, secret);
232
283
  } else {
233
284
  await this.contractStore.addContractInstance(instance);
234
285
  await this.contractStore.addContractArtifact(artifact);
235
286
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
236
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);
237
311
  }
238
312
 
239
- async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
313
+ private async registerContractAndAddAccount(
314
+ artifact: ContractArtifact,
315
+ instance: ContractInstanceWithAddress,
316
+ secret: Fr,
317
+ ) {
240
318
  const partialAddress = await computePartialAddress(instance);
241
319
 
242
320
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
@@ -263,12 +341,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
263
341
 
264
342
  async addAuthWitness(address: AztecAddress, messageHash: Fr) {
265
343
  const account = await this.accountStore.getAccount(address);
266
- 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);
267
346
 
268
347
  const schnorr = new Schnorr();
269
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
348
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
270
349
 
271
- const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
350
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
272
351
 
273
352
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
274
353
  }
@@ -299,13 +378,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
299
378
  }
300
379
 
301
380
  async privateCallNewFlow(
302
- from: AztecAddress,
381
+ from: AztecAddress | undefined,
303
382
  targetContractAddress: AztecAddress = AztecAddress.zero(),
304
383
  functionSelector: FunctionSelector = FunctionSelector.empty(),
305
384
  args: Fr[],
306
385
  argsHash: Fr = Fr.zero(),
307
386
  isStaticCall: boolean = false,
387
+ additionalScopes: AztecAddress[] = [],
308
388
  jobId: string,
389
+ authorizedUtilityCallTargets: AztecAddress[],
390
+ gasSettings: GasSettings,
309
391
  ) {
310
392
  this.logger.verbose(
311
393
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -319,12 +401,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
319
401
  throw new Error(message);
320
402
  }
321
403
 
322
- // When `from` is the zero address (e.g. when deploying a new account contract), we return an
323
- // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
324
- const effectiveScopes = from.isZero() ? [] : [from];
404
+ const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
325
405
 
326
406
  // Sync notes before executing private function to discover notes from previous transactions
327
- const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
407
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
328
408
  await this.executeUtilityCall(call, execScopes, jobId);
329
409
  };
330
410
 
@@ -335,16 +415,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
335
415
  utilityExecutor,
336
416
  blockHeader,
337
417
  jobId,
338
- effectiveScopes,
418
+ scopes,
339
419
  );
340
420
 
341
421
  const blockNumber = await this.getNextBlockNumber();
342
422
 
343
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
344
-
345
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
346
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
347
- 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);
348
425
 
349
426
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
350
427
 
@@ -359,6 +436,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
359
436
 
360
437
  const simulator = new WASMSimulator();
361
438
 
439
+ const transientArrayService = new TransientArrayService();
362
440
  const privateExecutionOracle = new PrivateExecutionOracle({
363
441
  argsHash,
364
442
  txContext,
@@ -378,18 +456,26 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
378
456
  senderTaggingStore: this.senderTaggingStore,
379
457
  recipientTaggingStore: this.recipientTaggingStore,
380
458
  senderAddressBookStore: this.senderAddressBookStore,
381
- capsuleStore: this.capsuleStore,
459
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
382
460
  privateEventStore: this.privateEventStore,
383
461
  contractSyncService: this.stateMachine.contractSyncService,
384
462
  jobId,
385
463
  totalPublicCalldataCount: 0,
386
464
  sideEffectCounter: minRevertibleSideEffectCounter,
387
- scopes: effectiveScopes,
465
+ scopes,
388
466
  // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
389
467
  // contract would perform, including setting senderForTags.
390
468
  senderForTags: from,
391
469
  simulator,
392
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,
393
479
  });
394
480
 
395
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.
@@ -412,7 +498,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
412
498
  );
413
499
  const publicFunctionsCalldata = await Promise.all(
414
500
  publicCallRequests.map(async r => {
415
- const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
501
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
416
502
  return new HashedValues(calldata, r.calldataHash);
417
503
  }),
418
504
  );
@@ -497,11 +583,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
497
583
  }
498
584
  }
499
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
+
500
592
  if (isStaticCall) {
501
593
  await checkpoint!.revert();
502
594
 
503
595
  await forkedWorldTrees.close();
504
- return executionResult.returnValues ?? [];
596
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
505
597
  }
506
598
 
507
599
  const txEffect = TxEffect.empty();
@@ -523,14 +615,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
523
615
 
524
616
  await forkedWorldTrees.close();
525
617
 
526
- return executionResult.returnValues ?? [];
618
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
527
619
  }
528
620
 
529
621
  async publicCallNewFlow(
530
- from: AztecAddress,
622
+ from: AztecAddress | undefined,
531
623
  targetContractAddress: AztecAddress,
532
624
  calldata: Fr[],
533
625
  isStaticCall: boolean,
626
+ gasSettings: GasSettings,
534
627
  ) {
535
628
  this.logger.verbose(
536
629
  `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -538,12 +631,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
538
631
 
539
632
  const blockNumber = await this.getNextBlockNumber();
540
633
 
541
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
542
-
543
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
544
-
545
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
546
-
547
634
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
548
635
 
549
636
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -595,7 +682,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
595
682
  // may require producing reverts.
596
683
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
597
684
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
598
- from,
685
+ from ?? AztecAddress.NULL_MSG_SENDER,
599
686
  targetContractAddress,
600
687
  isStaticCall,
601
688
  calldataHash,
@@ -686,6 +773,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
686
773
  functionSelector: FunctionSelector,
687
774
  args: Fr[],
688
775
  jobId: string,
776
+ authorizedUtilityCallTargets: AztecAddress[],
689
777
  ) {
690
778
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
691
779
  if (!artifact) {
@@ -702,7 +790,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
702
790
  },
703
791
  blockHeader,
704
792
  jobId,
705
- 'ALL_SCOPES',
793
+ await this.keyStore.getAccounts(),
706
794
  );
707
795
 
708
796
  const call = FunctionCall.from({
@@ -716,10 +804,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
716
804
  returnTypes: [],
717
805
  });
718
806
 
719
- return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
807
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
720
808
  }
721
809
 
722
- 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[]> {
723
816
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
724
817
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
725
818
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -732,6 +825,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
732
825
 
733
826
  try {
734
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
+ };
735
832
  const oracle = new UtilityExecutionOracle({
736
833
  contractAddress: call.to,
737
834
  authWitnesses: [],
@@ -744,15 +841,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
744
841
  aztecNode: this.stateMachine.node,
745
842
  recipientTaggingStore: this.recipientTaggingStore,
746
843
  senderAddressBookStore: this.senderAddressBookStore,
747
- capsuleStore: this.capsuleStore,
844
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
748
845
  privateEventStore: this.privateEventStore,
749
846
  messageContextService: this.stateMachine.messageContextService,
750
- contractSyncService: this.contractSyncService,
847
+ contractSyncService: this.stateMachine.contractSyncService,
848
+ l2TipsStore: this.stateMachine.l2TipsProvider,
751
849
  jobId,
752
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(),
753
858
  });
754
- const acirExecutionResult = await new WASMSimulator()
755
- .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
859
+ const acirExecutionResult = await simulator
860
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, buildACIRCallback(oracle))
756
861
  .catch((err: Error) => {
757
862
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
758
863
  throw new ExecutionError(
@@ -779,7 +884,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
779
884
  }
780
885
 
781
886
  private async getLastBlockNumber(): Promise<BlockNumber> {
782
- const header = await this.stateMachine.node.getBlockHeader('latest');
783
- 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
+ });
784
902
  }
785
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
+ }