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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dest/ContractClassRegistry-KKNT527R.js +3 -0
  2. package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
  4. package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
  5. package/dest/FeeJuice-GUJ5O6GB.js +3 -0
  6. package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
  8. package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
  9. package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
  10. package/dest/SchnorrAccount-QIXE5DXA.js.map +7 -0
  11. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  12. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  13. package/dest/bin/check_txe_oracle_version.js +32 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/chunk-BJVAAXNA.js +3 -0
  17. package/dest/chunk-BJVAAXNA.js.map +7 -0
  18. package/dest/chunk-DF6RMOC6.js +304 -0
  19. package/dest/chunk-DF6RMOC6.js.map +7 -0
  20. package/dest/chunk-PPJTNNUG.js +265 -0
  21. package/dest/chunk-PPJTNNUG.js.map +7 -0
  22. package/dest/constants.d.ts +3 -1
  23. package/dest/constants.d.ts.map +1 -1
  24. package/dest/constants.js +5 -0
  25. package/dest/dispatcher_pool.d.ts +67 -0
  26. package/dest/dispatcher_pool.d.ts.map +1 -0
  27. package/dest/dispatcher_pool.js +284 -0
  28. package/dest/index.d.ts +188 -7
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +160 -119
  31. package/dest/metafile.json +38147 -0
  32. package/dest/msgpackr_fr_extension.d.ts +2 -0
  33. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  34. package/dest/msgpackr_fr_extension.js +21 -0
  35. package/dest/oracle/interfaces.d.ts +39 -28
  36. package/dest/oracle/interfaces.d.ts.map +1 -1
  37. package/dest/oracle/txe_oracle_public_context.d.ts +18 -13
  38. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  39. package/dest/oracle/txe_oracle_public_context.js +27 -12
  40. package/dest/oracle/txe_oracle_top_level_context.d.ts +36 -20
  41. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  42. package/dest/oracle/txe_oracle_top_level_context.js +125 -66
  43. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  44. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  45. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  46. package/dest/rpc_server.d.ts +14 -0
  47. package/dest/rpc_server.d.ts.map +1 -0
  48. package/dest/rpc_server.js +78 -0
  49. package/dest/rpc_translator.d.ts +139 -83
  50. package/dest/rpc_translator.d.ts.map +1 -1
  51. package/dest/rpc_translator.js +568 -244
  52. package/dest/server.bundle.js +3 -0
  53. package/dest/server.bundle.js.map +7 -0
  54. package/dest/state_machine/archiver.d.ts +4 -4
  55. package/dest/state_machine/archiver.d.ts.map +1 -1
  56. package/dest/state_machine/archiver.js +22 -20
  57. package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
  58. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  59. package/dest/state_machine/dummy_p2p_client.js +16 -4
  60. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  61. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  62. package/dest/state_machine/global_variable_builder.js +9 -3
  63. package/dest/state_machine/index.d.ts +7 -3
  64. package/dest/state_machine/index.d.ts.map +1 -1
  65. package/dest/state_machine/index.js +23 -5
  66. package/dest/state_machine/mock_epoch_cache.d.ts +18 -3
  67. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  68. package/dest/state_machine/mock_epoch_cache.js +35 -2
  69. package/dest/state_machine/synchronizer.d.ts +5 -5
  70. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  71. package/dest/state_machine/synchronizer.js +4 -4
  72. package/dest/txe_oracle_version.d.ts +17 -0
  73. package/dest/txe_oracle_version.d.ts.map +1 -0
  74. package/dest/txe_oracle_version.js +14 -0
  75. package/dest/txe_session.d.ts +64 -6
  76. package/dest/txe_session.d.ts.map +1 -1
  77. package/dest/txe_session.js +159 -31
  78. package/dest/utils/encoding.d.ts +191 -0
  79. package/dest/utils/encoding.d.ts.map +1 -0
  80. package/dest/{util → utils}/encoding.js +7 -2
  81. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  82. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  83. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  84. package/dest/utils/txe_account_store.d.ts.map +1 -0
  85. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  86. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  87. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  88. package/dest/worker.bundle.js +3 -0
  89. package/dest/worker.bundle.js.map +7 -0
  90. package/dest/worker.d.ts +2 -0
  91. package/dest/worker.d.ts.map +1 -0
  92. package/dest/worker.js +92 -0
  93. package/package.json +37 -21
  94. package/src/bin/check_txe_oracle_version.ts +37 -0
  95. package/src/bin/index.ts +11 -2
  96. package/src/constants.ts +6 -0
  97. package/src/dispatcher_pool.ts +316 -0
  98. package/src/index.ts +178 -126
  99. package/src/msgpackr_fr_extension.ts +23 -0
  100. package/src/oracle/interfaces.ts +43 -34
  101. package/src/oracle/txe_oracle_public_context.ts +42 -12
  102. package/src/oracle/txe_oracle_top_level_context.ts +146 -77
  103. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  104. package/src/rpc_server.ts +87 -0
  105. package/src/rpc_translator.ts +647 -327
  106. package/src/state_machine/archiver.ts +33 -18
  107. package/src/state_machine/dummy_p2p_client.ts +31 -11
  108. package/src/state_machine/global_variable_builder.ts +18 -3
  109. package/src/state_machine/index.ts +25 -6
  110. package/src/state_machine/mock_epoch_cache.ts +46 -3
  111. package/src/state_machine/synchronizer.ts +5 -5
  112. package/src/txe_oracle_version.ts +17 -0
  113. package/src/txe_session.ts +253 -33
  114. package/src/{util → utils}/encoding.ts +8 -2
  115. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  116. package/src/worker.ts +98 -0
  117. package/dest/util/encoding.d.ts +0 -720
  118. package/dest/util/encoding.d.ts.map +0 -1
  119. package/dest/util/expected_failure_error.d.ts.map +0 -1
  120. package/dest/util/txe_account_store.d.ts.map +0 -1
  121. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  122. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  123. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  124. /package/dest/{util → utils}/txe_account_store.js +0 -0
  125. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  126. /package/src/{util → utils}/txe_account_store.ts +0 -0
package/dest/index.js CHANGED
@@ -1,14 +1,10 @@
1
- import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
2
1
  import { loadContractArtifact } from '@aztec/aztec.js/abi';
3
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
4
3
  import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
5
4
  import { Fr } from '@aztec/aztec.js/fields';
6
5
  import { PublicKeys, deriveKeys } from '@aztec/aztec.js/keys';
7
- import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
8
- import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
9
- import { protocolContractNames } from '@aztec/protocol-contracts';
10
- import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
11
- import { ContractStore } from '@aztec/pxe/server';
6
+ import { cloneEphemeralStoreFrom } from '@aztec/kv-store/lmdb-v2';
7
+ import { ContractStore } from '@aztec/pxe/client/lazy';
12
8
  import { computeArtifactHash } from '@aztec/stdlib/contract';
13
9
  import { zodFor } from '@aztec/stdlib/schemas';
14
10
  import { createHash } from 'crypto';
@@ -16,20 +12,55 @@ import { createReadStream } from 'fs';
16
12
  import { readFile, readdir } from 'fs/promises';
17
13
  import { join, parse } from 'path';
18
14
  import { z } from 'zod';
15
+ // Side-effect import: registers the msgpackr Fr extension for the bundled `Fr` class. Must
16
+ // be loaded before any `sendMessage` call. See msgpackr_fr_extension.ts for the why.
17
+ import './msgpackr_fr_extension.js';
19
18
  import { TXESession } from './txe_session.js';
20
- import { ForeignCallArgsSchema, ForeignCallResultSchema, fromArray, fromSingle, toSingle } from './util/encoding.js';
19
+ import { ForeignCallArgsSchema, ForeignCallResultSchema, addressFromSingle, fromArray, fromSingle, toSingle } from './utils/encoding.js';
20
+ // Protocol contracts TXE registers in its contract store. Only AuthRegistry is needed for the
21
+ // current test suites; add a contract here if a lookup against a `0x000…00X` address fails.
22
+ export const TXE_REQUIRED_PROTOCOL_CONTRACTS = [];
21
23
  const sessions = new Map();
22
- /*
23
- * TXE typically has to load the same contract artifacts over and over again for multiple tests,
24
- * so we cache them here to avoid loading from disk repeatedly.
25
- *
26
- * The in-flight map coalesces concurrent requests for the same cache key so that
27
- * computeArtifactHash (very expensive) is only run once even under parallelism.
28
- */ const TXEArtifactsCache = new Map();
29
- const TXEArtifactsCacheInFlight = new Map();
30
- const TXEForeignCallInputSchema = zodFor()(z.object({
24
+ /**
25
+ * Cache + in-flight map pair. Lookup hits the cache, then awaits an in-flight `compute()` if one
26
+ * exists, otherwise starts one and stores it. Guarantees `compute()` runs at most once per `key`
27
+ * across concurrent callers, which matters because `computeArtifactHash` is expensive.
28
+ */ class AsyncCache {
29
+ cache = new Map();
30
+ inFlight = new Map();
31
+ getOrCompute(key, compute) {
32
+ const cached = this.cache.get(key);
33
+ if (cached !== undefined) {
34
+ return Promise.resolve(cached);
35
+ }
36
+ let pending = this.inFlight.get(key);
37
+ if (!pending) {
38
+ pending = (async ()=>{
39
+ try {
40
+ const value = await compute();
41
+ this.cache.set(key, value);
42
+ return value;
43
+ } finally{
44
+ this.inFlight.delete(key);
45
+ }
46
+ })();
47
+ this.inFlight.set(key, pending);
48
+ }
49
+ return pending;
50
+ }
51
+ }
52
+ // Full deploys (artifact + computed instance), keyed by the full deploy context (contract +
53
+ // constructor args + publicKeys + salt + deployer). Hits on repeated identical deploys.
54
+ const TXEDeploymentsCache = new AsyncCache();
55
+ // Loaded + hashed contract artifact, keyed by compiled-bytecode hash. Hits across deploys of the
56
+ // same contract when constructor args / salt / deployer differ.
57
+ const TXEArtifactsCache = new AsyncCache();
58
+ export const TXEForeignCallInputSchema = zodFor()(z.object({
59
+ // Nargo generates session_id as a u64, which may exceed Number.MAX_SAFE_INTEGER.
60
+ // Zod 4's `.int()` enforces the safe-integer bound, so we drop it here and only require
61
+ // the value to be a non-negative number (it is used solely as a Map key).
31
62
  // eslint-disable-next-line camelcase
32
- session_id: z.number().int().nonnegative(),
63
+ session_id: z.number().nonnegative(),
33
64
  function: z.string(),
34
65
  // eslint-disable-next-line camelcase
35
66
  root_path: z.string(),
@@ -37,11 +68,30 @@ const TXEForeignCallInputSchema = zodFor()(z.object({
37
68
  package_name: z.string(),
38
69
  inputs: ForeignCallArgsSchema
39
70
  }));
40
- class TXEDispatcher {
71
+ export class TXEDispatcher {
41
72
  logger;
42
73
  contractStore;
43
- constructor(logger){
74
+ contractStoreSourceDir;
75
+ schnorrClassId;
76
+ constructor(logger, opts){
44
77
  this.logger = logger;
78
+ this.contractStoreSourceDir = opts.contractStoreSourceDir;
79
+ this.schnorrClassId = Fr.fromString(opts.schnorrClassId);
80
+ }
81
+ /**
82
+ * Clones the pre-populated LMDB at `contractStoreSourceDir` into a fresh per-instance tmpdir
83
+ * on first use, so this dispatcher has a writable store already containing the required
84
+ * protocol contracts + SchnorrAccount. Idempotent — subsequent calls are no-ops.
85
+ */ async warmUp() {
86
+ if (this.contractStore) {
87
+ return;
88
+ }
89
+ const t0 = Date.now();
90
+ const kvStore = await cloneEphemeralStoreFrom(join(this.contractStoreSourceDir, 'data.mdb'), 'txe-contracts', undefined, 2);
91
+ this.contractStore = new ContractStore(kvStore);
92
+ this.logger.debug('Cloned shared protocol-contracts store', {
93
+ totalMs: Date.now() - t0
94
+ });
45
95
  }
46
96
  fastHashFile(path) {
47
97
  return new Promise((resolve)=>{
@@ -59,6 +109,8 @@ class TXEDispatcher {
59
109
  const [contractPath, initializer] = inputs.slice(0, 2).map((input)=>fromArray(input).map((char)=>String.fromCharCode(char.toNumber())).join(''));
60
110
  const decodedArgs = fromArray(inputs[3]);
61
111
  const secret = fromSingle(inputs[4]);
112
+ const salt = fromSingle(inputs[5]);
113
+ const deployer = addressFromSingle(inputs[6]);
62
114
  const publicKeys = secret.equals(Fr.ZERO) ? PublicKeys.default() : (await deriveKeys(secret)).publicKeys;
63
115
  const publicKeysHash = await publicKeys.hash();
64
116
  let artifactPath = '';
@@ -84,89 +136,69 @@ class TXEDispatcher {
84
136
  artifactPath = join(rootPath, './target', `${packageName}-${contractFilename}.json`);
85
137
  }
86
138
  const fileHash = await this.fastHashFile(artifactPath);
87
- const cacheKey = `${contractDirectory ?? ''}-${contractFilename}-${initializer}-${decodedArgs.map((arg)=>arg.toString()).join('-')}-${publicKeysHash}-${fileHash}`;
88
- let instance;
89
- let artifact;
90
- if (TXEArtifactsCache.has(cacheKey)) {
91
- this.logger.debug(`Using cached artifact for ${cacheKey}`);
92
- ({ artifact, instance } = TXEArtifactsCache.get(cacheKey));
93
- } else {
94
- if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
95
- this.logger.debug(`Loading compiled artifact ${artifactPath}`);
96
- const compute = async ()=>{
97
- const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8'));
98
- const artifactWithoutHash = loadContractArtifact(artifactJSON);
99
- const computedArtifact = {
100
- ...artifactWithoutHash,
101
- // Artifact hash is *very* expensive to compute, so we do it here once
102
- // and the TXE contract data provider can cache it
103
- artifactHash: await computeArtifactHash(artifactWithoutHash)
104
- };
105
- this.logger.debug(`Deploy ${computedArtifact.name} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`);
106
- const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
107
- constructorArgs: decodedArgs,
108
- skipArgsDecoding: true,
109
- salt: Fr.ONE,
110
- publicKeys,
111
- constructorArtifact: initializer ? initializer : undefined,
112
- deployer: AztecAddress.ZERO
113
- });
114
- const result = {
115
- artifact: computedArtifact,
116
- instance: computedInstance
117
- };
118
- TXEArtifactsCache.set(cacheKey, result);
119
- TXEArtifactsCacheInFlight.delete(cacheKey);
120
- return result;
139
+ const cacheKey = `${contractDirectory ?? ''}-${contractFilename}-${initializer}-${decodedArgs.map((arg)=>arg.toString()).join('-')}-${publicKeysHash}-${salt}-${deployer}-${fileHash}`;
140
+ const { artifact, instance } = await TXEDeploymentsCache.getOrCompute(cacheKey, async ()=>{
141
+ this.logger.debug(`Loading compiled artifact ${artifactPath}`);
142
+ // Inner cache: artifact load + hash depends only on the compiled bytecode (`fileHash`), so
143
+ // subsequent deploys of the same contract — regardless of constructor args / deployer /
144
+ // salt reuse the same `ContractArtifactWithHash`.
145
+ const computedArtifact = await TXEArtifactsCache.getOrCompute(fileHash, async ()=>{
146
+ const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8'));
147
+ const artifactWithoutHash = loadContractArtifact(artifactJSON);
148
+ return {
149
+ ...artifactWithoutHash,
150
+ artifactHash: await computeArtifactHash(artifactWithoutHash)
121
151
  };
122
- TXEArtifactsCacheInFlight.set(cacheKey, compute());
123
- }
124
- ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey));
125
- }
152
+ });
153
+ this.logger.debug(`Deploy ${computedArtifact.name} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`);
154
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
155
+ constructorArgs: decodedArgs,
156
+ skipArgsDecoding: true,
157
+ salt,
158
+ publicKeys,
159
+ constructorArtifact: initializer ? initializer : undefined,
160
+ deployer
161
+ });
162
+ return {
163
+ artifact: computedArtifact,
164
+ instance: computedInstance
165
+ };
166
+ });
126
167
  inputs.splice(0, 1, artifact, instance, toSingle(secret));
127
168
  }
128
169
  async #processAddAccountInputs({ inputs }) {
129
170
  const secret = fromSingle(inputs[0]);
130
171
  const cacheKey = `SchnorrAccountContract-${secret}`;
131
- let artifact;
132
- let instance;
133
- if (TXEArtifactsCache.has(cacheKey)) {
134
- this.logger.debug(`Using cached artifact for ${cacheKey}`);
135
- ({ artifact, instance } = TXEArtifactsCache.get(cacheKey));
136
- } else {
137
- if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
138
- const compute = async ()=>{
139
- const keys = await deriveKeys(secret);
140
- const args = [
141
- keys.publicKeys.masterIncomingViewingPublicKey.x,
142
- keys.publicKeys.masterIncomingViewingPublicKey.y
143
- ];
144
- const computedArtifact = {
145
- ...SchnorrAccountContractArtifact,
146
- // Artifact hash is *very* expensive to compute, so we do it here once
147
- // and the TXE contract data provider can cache it
148
- artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact)
149
- };
150
- const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
151
- constructorArgs: args,
152
- skipArgsDecoding: true,
153
- salt: Fr.ONE,
154
- publicKeys: keys.publicKeys,
155
- constructorArtifact: 'constructor',
156
- deployer: AztecAddress.ZERO
157
- });
158
- const result = {
159
- artifact: computedArtifact,
160
- instance: computedInstance
161
- };
162
- TXEArtifactsCache.set(cacheKey, result);
163
- TXEArtifactsCacheInFlight.delete(cacheKey);
164
- return result;
165
- };
166
- TXEArtifactsCacheInFlight.set(cacheKey, compute());
172
+ const { artifact, instance } = await TXEDeploymentsCache.getOrCompute(cacheKey, async ()=>{
173
+ const [artifactFromStore, classWithPreimage] = await Promise.all([
174
+ this.contractStore.getContractArtifact(this.schnorrClassId),
175
+ this.contractStore.getContractClassWithPreimage(this.schnorrClassId)
176
+ ]);
177
+ if (!artifactFromStore || !classWithPreimage) {
178
+ throw new Error(`SchnorrAccount not found in shared contract store at class id ${this.schnorrClassId.toString()}`);
167
179
  }
168
- ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey));
169
- }
180
+ const computedArtifact = {
181
+ ...artifactFromStore,
182
+ artifactHash: classWithPreimage.artifactHash
183
+ };
184
+ const keys = await deriveKeys(secret);
185
+ const args = [
186
+ keys.publicKeys.ivpkM.x,
187
+ keys.publicKeys.ivpkM.y
188
+ ];
189
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
190
+ constructorArgs: args,
191
+ skipArgsDecoding: true,
192
+ salt: Fr.ONE,
193
+ publicKeys: keys.publicKeys,
194
+ constructorArtifact: 'constructor',
195
+ deployer: AztecAddress.ZERO
196
+ });
197
+ return {
198
+ artifact: computedArtifact,
199
+ instance: computedInstance
200
+ };
201
+ });
170
202
  inputs.splice(0, 0, artifact, instance);
171
203
  }
172
204
  // eslint-disable-next-line camelcase
@@ -175,26 +207,16 @@ class TXEDispatcher {
175
207
  this.logger.debug(`Calling ${functionName} on session ${sessionId}`);
176
208
  if (!sessions.has(sessionId)) {
177
209
  this.logger.debug(`Creating new session ${sessionId}`);
178
- if (!this.contractStore) {
179
- const kvStore = await openTmpStore('txe-contracts');
180
- this.contractStore = new ContractStore(kvStore);
181
- const provider = new BundledProtocolContractsProvider();
182
- for (const name of protocolContractNames){
183
- const { instance, artifact } = await provider.getProtocolContractArtifact(name);
184
- await this.contractStore.addContractArtifact(artifact);
185
- await this.contractStore.addContractInstance(instance);
186
- }
187
- this.logger.debug('Registered protocol contracts in shared contract store');
188
- }
210
+ await this.warmUp();
189
211
  sessions.set(sessionId, await TXESession.init(this.contractStore));
190
212
  }
191
213
  switch(functionName){
192
- case 'txeDeploy':
214
+ case 'aztec_txe_deploy':
193
215
  {
194
216
  await this.#processDeployInputs(callData);
195
217
  break;
196
218
  }
197
- case 'txeAddAccount':
219
+ case 'aztec_txe_addAccount':
198
220
  {
199
221
  await this.#processAddAccountInputs(callData);
200
222
  break;
@@ -202,17 +224,36 @@ class TXEDispatcher {
202
224
  }
203
225
  return await sessions.get(sessionId).processFunction(functionName, inputs);
204
226
  }
227
+ /**
228
+ * Releases a session and its resources (per-session LMDB + `NativeWorldStateService`).
229
+ * Called by the dispatcher pool when nargo closes its TCP connection for a test (see
230
+ * `rpc_server.ts`'s socket tracker). No-op if the session was never created — that happens
231
+ * when nargo opens a connection but errors before sending a request.
232
+ */ async disposeSession(sessionId) {
233
+ const session = sessions.get(sessionId);
234
+ if (!session) {
235
+ return;
236
+ }
237
+ sessions.delete(sessionId);
238
+ await session.dispose();
239
+ }
205
240
  }
206
- const TXEDispatcherApiSchema = {
241
+ /** Diagnostic-only: number of sessions currently held by this worker. */ export function activeSessionCount() {
242
+ return sessions.size;
243
+ }
244
+ export const TXEDispatcherApiSchema = {
207
245
  // eslint-disable-next-line camelcase
208
- resolve_foreign_call: z.function().args(TXEForeignCallInputSchema).returns(ForeignCallResultSchema)
246
+ resolve_foreign_call: z.function({
247
+ input: z.tuple([
248
+ TXEForeignCallInputSchema
249
+ ]),
250
+ output: ForeignCallResultSchema
251
+ }),
252
+ // disposeSession is invoked over IPC from the worker, not via RPC; required by ApiSchemaFor.
253
+ disposeSession: z.function({
254
+ input: z.tuple([
255
+ z.number().nonnegative()
256
+ ]),
257
+ output: z.void()
258
+ })
209
259
  };
210
- /**
211
- * Creates an RPC server that forwards calls to the TXE.
212
- * @param logger - Logger to output to
213
- * @returns A TXE RPC server.
214
- */ export function createTXERpcServer(logger) {
215
- return createSafeJsonRpcServer(new TXEDispatcher(logger), TXEDispatcherApiSchema, {
216
- http200OnError: true
217
- });
218
- }