@aztec/txe 0.0.1-commit.b6e433891 → 0.0.1-commit.b9865e97

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 (148) hide show
  1. package/dest/ContractClassRegistry-PII7Q556.js +3 -0
  2. package/dest/ContractClassRegistry-PII7Q556.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-3MHLGFNZ.js +3 -0
  4. package/dest/ContractInstanceRegistry-3MHLGFNZ.js.map +7 -0
  5. package/dest/FeeJuice-TQV5AQK7.js +3 -0
  6. package/dest/FeeJuice-TQV5AQK7.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-SBJUIJY7.js +3 -0
  8. package/dest/MultiCallEntrypoint-SBJUIJY7.js.map +7 -0
  9. package/dest/SchnorrAccount-MQXPIZ44.js +3 -0
  10. package/dest/SchnorrAccount-MQXPIZ44.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 +61 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/bin/oracle_test_server.d.ts +3 -0
  17. package/dest/bin/oracle_test_server.d.ts.map +1 -0
  18. package/dest/bin/oracle_test_server.js +41 -0
  19. package/dest/chunk-BJVAAXNA.js +3 -0
  20. package/dest/chunk-BJVAAXNA.js.map +7 -0
  21. package/dest/chunk-CUSVOJA4.js +304 -0
  22. package/dest/chunk-CUSVOJA4.js.map +7 -0
  23. package/dest/chunk-OYLIPWI6.js +260 -0
  24. package/dest/chunk-OYLIPWI6.js.map +7 -0
  25. package/dest/constants.d.ts +5 -1
  26. package/dest/constants.d.ts.map +1 -1
  27. package/dest/constants.js +8 -0
  28. package/dest/dispatcher_pool.d.ts +67 -0
  29. package/dest/dispatcher_pool.d.ts.map +1 -0
  30. package/dest/dispatcher_pool.js +284 -0
  31. package/dest/index.d.ts +185 -7
  32. package/dest/index.d.ts.map +1 -1
  33. package/dest/index.js +70 -190
  34. package/dest/metafile.json +36863 -0
  35. package/dest/msgpackr_fr_extension.d.ts +2 -0
  36. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  37. package/dest/msgpackr_fr_extension.js +21 -0
  38. package/dest/oracle/interfaces.d.ts +33 -8
  39. package/dest/oracle/interfaces.d.ts.map +1 -1
  40. package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
  41. package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
  42. package/dest/oracle/test-resolver/fixtures.js +39 -0
  43. package/dest/oracle/test-resolver/index.d.ts +9 -0
  44. package/dest/oracle/test-resolver/index.d.ts.map +1 -0
  45. package/dest/oracle/test-resolver/index.js +33 -0
  46. package/dest/oracle/test-resolver/resolver.d.ts +34 -0
  47. package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
  48. package/dest/oracle/test-resolver/resolver.js +114 -0
  49. package/dest/oracle/txe_oracle_public_context.d.ts +26 -2
  50. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  51. package/dest/oracle/txe_oracle_public_context.js +43 -1
  52. package/dest/oracle/txe_oracle_registry.d.ts +147 -0
  53. package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
  54. package/dest/oracle/txe_oracle_registry.js +562 -0
  55. package/dest/oracle/txe_oracle_top_level_context.d.ts +33 -14
  56. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  57. package/dest/oracle/txe_oracle_top_level_context.js +149 -60
  58. package/dest/oracle/txe_oracle_version.d.ts +17 -0
  59. package/dest/oracle/txe_oracle_version.d.ts.map +1 -0
  60. package/dest/oracle/txe_oracle_version.js +14 -0
  61. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  62. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  63. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  64. package/dest/rpc_server.d.ts +14 -0
  65. package/dest/rpc_server.d.ts.map +1 -0
  66. package/dest/rpc_server.js +78 -0
  67. package/dest/rpc_translator.d.ts +96 -233
  68. package/dest/rpc_translator.d.ts.map +1 -1
  69. package/dest/rpc_translator.js +706 -637
  70. package/dest/server.bundle.js +3 -0
  71. package/dest/server.bundle.js.map +7 -0
  72. package/dest/state_machine/archiver.d.ts +4 -3
  73. package/dest/state_machine/archiver.d.ts.map +1 -1
  74. package/dest/state_machine/archiver.js +26 -15
  75. package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
  76. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  77. package/dest/state_machine/dummy_p2p_client.js +16 -4
  78. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  79. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  80. package/dest/state_machine/global_variable_builder.js +9 -3
  81. package/dest/state_machine/index.d.ts +4 -2
  82. package/dest/state_machine/index.d.ts.map +1 -1
  83. package/dest/state_machine/index.js +17 -3
  84. package/dest/state_machine/mock_epoch_cache.d.ts +1 -2
  85. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  86. package/dest/state_machine/mock_epoch_cache.js +0 -3
  87. package/dest/state_machine/synchronizer.js +1 -1
  88. package/dest/txe_session.d.ts +75 -14
  89. package/dest/txe_session.d.ts.map +1 -1
  90. package/dest/txe_session.js +170 -41
  91. package/dest/utils/encoding.d.ts +191 -0
  92. package/dest/utils/encoding.d.ts.map +1 -0
  93. package/dest/{util → utils}/encoding.js +7 -2
  94. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  95. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  96. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  97. package/dest/utils/txe_account_store.d.ts.map +1 -0
  98. package/dest/utils/txe_artifact_resolver.d.ts +37 -0
  99. package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
  100. package/dest/utils/txe_artifact_resolver.js +161 -0
  101. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  102. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  103. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  104. package/dest/worker.bundle.js +3 -0
  105. package/dest/worker.bundle.js.map +7 -0
  106. package/dest/worker.d.ts +2 -0
  107. package/dest/worker.d.ts.map +1 -0
  108. package/dest/worker.js +92 -0
  109. package/package.json +38 -21
  110. package/src/bin/check_txe_oracle_version.ts +70 -0
  111. package/src/bin/index.ts +11 -2
  112. package/src/bin/oracle_test_server.ts +51 -0
  113. package/src/constants.ts +10 -0
  114. package/src/dispatcher_pool.ts +316 -0
  115. package/src/index.ts +97 -227
  116. package/src/msgpackr_fr_extension.ts +23 -0
  117. package/src/oracle/interfaces.ts +29 -7
  118. package/src/oracle/test-resolver/fixtures.ts +84 -0
  119. package/src/oracle/test-resolver/index.ts +45 -0
  120. package/src/oracle/test-resolver/resolver.ts +165 -0
  121. package/src/oracle/txe_oracle_public_context.ts +60 -0
  122. package/src/oracle/txe_oracle_registry.ts +401 -0
  123. package/src/oracle/txe_oracle_top_level_context.ts +180 -67
  124. package/src/oracle/txe_oracle_version.ts +17 -0
  125. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  126. package/src/rpc_server.ts +87 -0
  127. package/src/rpc_translator.ts +787 -925
  128. package/src/state_machine/archiver.ts +38 -16
  129. package/src/state_machine/dummy_p2p_client.ts +31 -11
  130. package/src/state_machine/global_variable_builder.ts +18 -3
  131. package/src/state_machine/index.ts +20 -5
  132. package/src/state_machine/mock_epoch_cache.ts +0 -4
  133. package/src/state_machine/synchronizer.ts +1 -1
  134. package/src/txe_session.ts +278 -45
  135. package/src/{util → utils}/encoding.ts +8 -2
  136. package/src/utils/txe_artifact_resolver.ts +217 -0
  137. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  138. package/src/worker.ts +98 -0
  139. package/dest/util/encoding.d.ts +0 -720
  140. package/dest/util/encoding.d.ts.map +0 -1
  141. package/dest/util/expected_failure_error.d.ts.map +0 -1
  142. package/dest/util/txe_account_store.d.ts.map +0 -1
  143. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  144. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  145. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  146. /package/dest/{util → utils}/txe_account_store.js +0 -0
  147. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  148. /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 {
@@ -47,10 +45,10 @@ import {
47
45
  witnessMapToFields,
48
46
  } from '@aztec/simulator/client';
49
47
  import {
50
- CppPublicTxSimulator,
51
48
  GuardedMerkleTreeOperations,
52
49
  PublicContractsDB,
53
50
  PublicProcessor,
51
+ PublicTxSimulator,
54
52
  } from '@aztec/simulator/server';
55
53
  import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
56
54
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
@@ -65,6 +63,7 @@ import {
65
63
  PrivateToPublicAccumulatedData,
66
64
  PublicCallRequest,
67
65
  } from '@aztec/stdlib/kernel';
66
+ import { hashPublicKey } from '@aztec/stdlib/keys';
68
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
69
68
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
70
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
@@ -81,13 +80,14 @@ import {
81
80
  collectNested,
82
81
  } from '@aztec/stdlib/tx';
83
82
  import type { UInt64 } from '@aztec/stdlib/types';
84
- import { ForkCheckpoint } from '@aztec/world-state';
83
+ import { ForkCheckpoint } from '@aztec/world-state/native';
85
84
 
86
- import { DEFAULT_ADDRESS } from '../constants.js';
85
+ import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
87
86
  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
87
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
88
+ import type { TXEAccountStore } from '../utils/txe_account_store.js';
89
+ import type { TXEArtifactResolver } from '../utils/txe_artifact_resolver.js';
90
+ import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
91
91
  import type { ITxeExecutionOracle } from './interfaces.js';
92
92
 
93
93
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -112,18 +112,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
112
112
  private version: Fr,
113
113
  private chainId: Fr,
114
114
  private authwits: Map<string, AuthWitness>,
115
- private readonly contractSyncService: ContractSyncService,
115
+ private readonly artifactResolver: TXEArtifactResolver,
116
+ private readonly rootPath: string,
117
+ private readonly packageName: string,
116
118
  ) {
117
119
  this.logger = createLogger('txe:top_level_context');
118
120
  this.logger.debug('Entering Top Level Context');
119
121
  }
120
122
 
121
- assertCompatibleOracleVersion(version: number): void {
122
- if (version !== ORACLE_VERSION) {
123
+ private contractOracleVersion: { major: number; minor: number } | undefined;
124
+
125
+ assertCompatibleOracleVersion(major: number, minor: number): void {
126
+ if (major !== ORACLE_VERSION_MAJOR) {
127
+ const hint =
128
+ major > ORACLE_VERSION_MAJOR
129
+ ? '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.'
130
+ : '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
131
  throw new Error(
124
- `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
132
+ `Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
125
133
  );
126
134
  }
135
+ this.contractOracleVersion = { major, minor };
136
+ }
137
+
138
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
139
+ nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
140
+ return this.contractOracleVersion;
127
141
  }
128
142
 
129
143
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
@@ -133,7 +147,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
133
147
  }
134
148
 
135
149
  // 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> {
150
+ log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
137
151
  if (!LogLevels[level]) {
138
152
  throw new Error(`Invalid log level: ${level}`);
139
153
  }
@@ -156,12 +170,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
170
  }
157
171
 
158
172
  async getLastBlockTimestamp() {
159
- return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
173
+ return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
160
174
  }
161
175
 
162
176
  async getLastTxEffects() {
163
177
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
164
- const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
178
+ const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
165
179
 
166
180
  if (block!.body.txEffects.length != 1) {
167
181
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -170,7 +184,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
170
184
 
171
185
  const txEffects = block!.body.txEffects[0];
172
186
 
173
- return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
187
+ const privateLogs = txEffects.privateLogs;
188
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
189
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
190
+ }
191
+
192
+ return {
193
+ txHash: txEffects.txHash,
194
+ noteHashes: txEffects.noteHashes,
195
+ nullifiers: txEffects.nullifiers,
196
+ privateLogs,
197
+ };
174
198
  }
175
199
 
176
200
  async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
@@ -193,7 +217,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
193
217
  }
194
218
 
195
219
  async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
196
- return (
220
+ const events = (
197
221
  await this.privateEventStore.getPrivateEvents(selector, {
198
222
  contractAddress,
199
223
  scopes: [scope],
@@ -201,6 +225,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
201
225
  toBlock: (await this.getLastBlockNumber()) + 1,
202
226
  })
203
227
  ).map(e => e.packedEvent);
228
+
229
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
230
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
231
+ }
232
+ if (events.some(e => e.length > MAX_PRIVATE_EVENT_LEN)) {
233
+ throw new Error(`Some private event has length larger than maxLen ${MAX_PRIVATE_EVENT_LEN}`);
234
+ }
235
+
236
+ return events;
204
237
  }
205
238
 
206
239
  async advanceBlocksBy(blocks: number) {
@@ -216,27 +249,71 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
216
249
  this.nextBlockTimestamp += duration;
217
250
  }
218
251
 
219
- async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
252
+ private deploymentNullifier(address: AztecAddress): Promise<Fr> {
253
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
254
+ }
255
+
256
+ async deploy(
257
+ contractPath: string,
258
+ initializer: string,
259
+ args: Fr[],
260
+ secret: Fr,
261
+ salt: Fr,
262
+ deployer: AztecAddress,
263
+ ): Promise<Fr[]> {
264
+ const { artifact, instance } = await this.artifactResolver.resolveDeployArtifact({
265
+ rootPath: this.rootPath,
266
+ packageName: this.packageName,
267
+ contractPath,
268
+ initializer,
269
+ args,
270
+ secret,
271
+ salt,
272
+ deployer,
273
+ });
274
+
220
275
  // Emit deployment nullifier
221
276
  await this.mineBlock({
222
- nullifiers: [
223
- await siloNullifier(
224
- AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
225
- instance.address.toField(),
226
- ),
227
- ],
277
+ nullifiers: [await this.deploymentNullifier(instance.address)],
228
278
  });
229
279
 
230
280
  if (!secret.equals(Fr.ZERO)) {
231
- await this.addAccount(artifact, instance, secret);
281
+ await this.registerContractAndAddAccount(artifact, instance, secret);
232
282
  } else {
233
283
  await this.contractStore.addContractInstance(instance);
234
284
  await this.contractStore.addContractArtifact(artifact);
235
285
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
236
286
  }
287
+
288
+ return [
289
+ instance.salt,
290
+ instance.deployer.toField(),
291
+ instance.currentContractClassId,
292
+ instance.initializationHash,
293
+ instance.immutablesHash,
294
+ ...instance.publicKeys.toFields(),
295
+ ];
296
+ }
297
+
298
+ /**
299
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
300
+ */
301
+ async mineDeploymentNullifiers(addresses: AztecAddress[]) {
302
+ await this.mineBlock({
303
+ nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
304
+ });
305
+ }
306
+
307
+ async addAccount(secret: Fr) {
308
+ const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
309
+ return this.registerContractAndAddAccount(artifact, instance, secret);
237
310
  }
238
311
 
239
- async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
312
+ private async registerContractAndAddAccount(
313
+ artifact: ContractArtifact,
314
+ instance: ContractInstanceWithAddress,
315
+ secret: Fr,
316
+ ) {
240
317
  const partialAddress = await computePartialAddress(instance);
241
318
 
242
319
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
@@ -263,12 +340,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
263
340
 
264
341
  async addAuthWitness(address: AztecAddress, messageHash: Fr) {
265
342
  const account = await this.accountStore.getAccount(address);
266
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
343
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
344
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
267
345
 
268
346
  const schnorr = new Schnorr();
269
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
347
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
270
348
 
271
- const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
349
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
272
350
 
273
351
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
274
352
  }
@@ -299,13 +377,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
299
377
  }
300
378
 
301
379
  async privateCallNewFlow(
302
- from: AztecAddress,
380
+ from: AztecAddress | undefined,
303
381
  targetContractAddress: AztecAddress = AztecAddress.zero(),
304
382
  functionSelector: FunctionSelector = FunctionSelector.empty(),
305
383
  args: Fr[],
306
384
  argsHash: Fr = Fr.zero(),
307
385
  isStaticCall: boolean = false,
386
+ additionalScopes: AztecAddress[] = [],
308
387
  jobId: string,
388
+ authorizedUtilityCallTargets: AztecAddress[],
389
+ gasSettings: GasSettings,
309
390
  ) {
310
391
  this.logger.verbose(
311
392
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -319,12 +400,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
319
400
  throw new Error(message);
320
401
  }
321
402
 
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];
403
+ const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
325
404
 
326
405
  // Sync notes before executing private function to discover notes from previous transactions
327
- const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
406
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
328
407
  await this.executeUtilityCall(call, execScopes, jobId);
329
408
  };
330
409
 
@@ -335,16 +414,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
335
414
  utilityExecutor,
336
415
  blockHeader,
337
416
  jobId,
338
- effectiveScopes,
417
+ scopes,
339
418
  );
340
419
 
341
420
  const blockNumber = await this.getNextBlockNumber();
342
421
 
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());
422
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
423
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
348
424
 
349
425
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
350
426
 
@@ -378,18 +454,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
378
454
  senderTaggingStore: this.senderTaggingStore,
379
455
  recipientTaggingStore: this.recipientTaggingStore,
380
456
  senderAddressBookStore: this.senderAddressBookStore,
381
- capsuleStore: this.capsuleStore,
457
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
382
458
  privateEventStore: this.privateEventStore,
383
459
  contractSyncService: this.stateMachine.contractSyncService,
384
460
  jobId,
385
461
  totalPublicCalldataCount: 0,
386
462
  sideEffectCounter: minRevertibleSideEffectCounter,
387
- scopes: effectiveScopes,
463
+ scopes,
388
464
  // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
389
465
  // contract would perform, including setting senderForTags.
390
466
  senderForTags: from,
391
467
  simulator,
392
468
  messageContextService: this.stateMachine.messageContextService,
469
+ l2TipsStore: this.stateMachine.l2TipsProvider,
470
+ hooks: composeHooks({
471
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
472
+ isStaticCall ? 'private view' : 'private',
473
+ authorizedUtilityCallTargets,
474
+ ),
475
+ }),
393
476
  });
394
477
 
395
478
  // 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 +495,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
412
495
  );
413
496
  const publicFunctionsCalldata = await Promise.all(
414
497
  publicCallRequests.map(async r => {
415
- const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
498
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
416
499
  return new HashedValues(calldata, r.calldataHash);
417
500
  }),
418
501
  );
@@ -460,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
460
543
  globals,
461
544
  guardedMerkleTrees,
462
545
  contractsDB,
463
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
546
+ new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
464
547
  new TestDateProvider(),
465
548
  undefined,
466
549
  createLogger('simulator:public-processor', bindings),
@@ -497,11 +580,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
497
580
  }
498
581
  }
499
582
 
583
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
584
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
585
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
586
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
587
+ const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
588
+
500
589
  if (isStaticCall) {
501
590
  await checkpoint!.revert();
502
591
 
503
592
  await forkedWorldTrees.close();
504
- return executionResult.returnValues ?? [];
593
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
505
594
  }
506
595
 
507
596
  const txEffect = TxEffect.empty();
@@ -523,14 +612,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
523
612
 
524
613
  await forkedWorldTrees.close();
525
614
 
526
- return executionResult.returnValues ?? [];
615
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
527
616
  }
528
617
 
529
618
  async publicCallNewFlow(
530
- from: AztecAddress,
619
+ from: AztecAddress | undefined,
531
620
  targetContractAddress: AztecAddress,
532
621
  calldata: Fr[],
533
622
  isStaticCall: boolean,
623
+ gasSettings: GasSettings,
534
624
  ) {
535
625
  this.logger.verbose(
536
626
  `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -538,12 +628,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
538
628
 
539
629
  const blockNumber = await this.getNextBlockNumber();
540
630
 
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
631
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
548
632
 
549
633
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -573,7 +657,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
573
657
  collectStatistics: false,
574
658
  collectCallMetadata: true,
575
659
  });
576
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
660
+ const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
577
661
  const processor = new PublicProcessor(
578
662
  globals,
579
663
  guardedMerkleTrees,
@@ -595,7 +679,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
595
679
  // may require producing reverts.
596
680
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
597
681
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
598
- from,
682
+ from ?? AztecAddress.NULL_MSG_SENDER,
599
683
  targetContractAddress,
600
684
  isStaticCall,
601
685
  calldataHash,
@@ -686,6 +770,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
686
770
  functionSelector: FunctionSelector,
687
771
  args: Fr[],
688
772
  jobId: string,
773
+ authorizedUtilityCallTargets: AztecAddress[],
689
774
  ) {
690
775
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
691
776
  if (!artifact) {
@@ -702,7 +787,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
702
787
  },
703
788
  blockHeader,
704
789
  jobId,
705
- 'ALL_SCOPES',
790
+ await this.keyStore.getAccounts(),
706
791
  );
707
792
 
708
793
  const call = FunctionCall.from({
@@ -716,10 +801,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
716
801
  returnTypes: [],
717
802
  });
718
803
 
719
- return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
804
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
720
805
  }
721
806
 
722
- private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
807
+ private async executeUtilityCall(
808
+ call: FunctionCall,
809
+ scopes: AztecAddress[],
810
+ jobId: string,
811
+ authorizedUtilityCallTargets: AztecAddress[] = [],
812
+ ): Promise<Fr[]> {
723
813
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
724
814
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
725
815
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -732,6 +822,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
732
822
 
733
823
  try {
734
824
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
825
+ const simulator = new WASMSimulator();
826
+ const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
827
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
828
+ };
735
829
  const oracle = new UtilityExecutionOracle({
736
830
  contractAddress: call.to,
737
831
  authWitnesses: [],
@@ -744,14 +838,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
744
838
  aztecNode: this.stateMachine.node,
745
839
  recipientTaggingStore: this.recipientTaggingStore,
746
840
  senderAddressBookStore: this.senderAddressBookStore,
747
- capsuleStore: this.capsuleStore,
841
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
748
842
  privateEventStore: this.privateEventStore,
749
843
  messageContextService: this.stateMachine.messageContextService,
750
- contractSyncService: this.contractSyncService,
844
+ contractSyncService: this.stateMachine.contractSyncService,
845
+ l2TipsStore: this.stateMachine.l2TipsProvider,
751
846
  jobId,
752
847
  scopes,
848
+ simulator,
849
+ hooks: composeHooks({
850
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
851
+ }),
852
+ utilityExecutor,
753
853
  });
754
- const acirExecutionResult = await new WASMSimulator()
854
+ const acirExecutionResult = await simulator
755
855
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
756
856
  .catch((err: Error) => {
757
857
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
@@ -779,7 +879,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
779
879
  }
780
880
 
781
881
  private async getLastBlockNumber(): Promise<BlockNumber> {
782
- const header = await this.stateMachine.node.getBlockHeader('latest');
783
- return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
882
+ const block = await this.stateMachine.node.getBlock('latest');
883
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
884
+ }
885
+
886
+ private buildAuthorizeUtilityCallHook(
887
+ callerContext: 'private' | 'private view' | 'utility',
888
+ authorizedTargets: AztecAddress[],
889
+ ): ExecutionHooks['authorizeUtilityCall'] | undefined {
890
+ if (authorizedTargets.length === 0) {
891
+ return undefined;
892
+ }
893
+ return req =>
894
+ Promise.resolve({
895
+ authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
896
+ });
784
897
  }
785
898
  }
@@ -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
+ }