@sip-protocol/sdk 0.7.2 → 0.7.4

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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,644 @@
1
+ /**
2
+ * Worker Pool for Parallel Proof Generation
3
+ *
4
+ * @module proofs/parallel/worker-pool
5
+ * @description Manages a pool of workers for parallel proof generation
6
+ *
7
+ * M20-12: Optimize proof generation parallelization (#307)
8
+ */
9
+
10
+ import type { SingleProof } from '@sip-protocol/types'
11
+ import type {
12
+ WorkerStatus,
13
+ WorkerInfo,
14
+ WorkerPoolConfig,
15
+ WorkerPoolStats,
16
+ ProofTask,
17
+ TaskSubmitOptions,
18
+ IWorkerPool,
19
+ WorkStealEvent,
20
+ WorkerStealingStats,
21
+ IWorkStealingScheduler,
22
+ } from './interface'
23
+ import { DEFAULT_WORKER_POOL_CONFIG } from './interface'
24
+ import type { ComposableProofProvider } from '../composer'
25
+
26
+ // ─── Worker Implementation ───────────────────────────────────────────────────
27
+
28
+ interface WorkerState {
29
+ id: string
30
+ status: WorkerStatus
31
+ currentTask: ProofTask | null
32
+ taskQueue: ProofTask[]
33
+ tasksCompleted: number
34
+ totalExecutionTime: number
35
+ memoryUsage: number
36
+ createdAt: number
37
+ lastActiveAt: number
38
+ }
39
+
40
+ // ─── Work Stealing Scheduler ─────────────────────────────────────────────────
41
+
42
+ /**
43
+ * Manages work stealing between workers for load balancing
44
+ */
45
+ export class WorkStealingScheduler implements IWorkStealingScheduler {
46
+ private readonly workers = new Map<string, WorkerState>()
47
+ private readonly stealHistory: WorkStealEvent[] = []
48
+ private readonly maxHistorySize = 1000
49
+
50
+ /**
51
+ * Register a worker with the scheduler
52
+ */
53
+ registerWorker(worker: WorkerState): void {
54
+ this.workers.set(worker.id, worker)
55
+ }
56
+
57
+ /**
58
+ * Unregister a worker from the scheduler
59
+ */
60
+ unregisterWorker(workerId: string): void {
61
+ this.workers.delete(workerId)
62
+ }
63
+
64
+ /**
65
+ * Assign a task to the best available worker
66
+ */
67
+ assign(task: ProofTask): string | null {
68
+ // Find worker with shortest queue
69
+ let bestWorker: WorkerState | null = null
70
+ let shortestQueue = Infinity
71
+
72
+ for (const worker of this.workers.values()) {
73
+ if (worker.status === 'idle' || worker.status === 'busy') {
74
+ const queueLength = worker.taskQueue.length + (worker.currentTask ? 1 : 0)
75
+ if (queueLength < shortestQueue) {
76
+ shortestQueue = queueLength
77
+ bestWorker = worker
78
+ }
79
+ }
80
+ }
81
+
82
+ if (bestWorker) {
83
+ bestWorker.taskQueue.push(task)
84
+ return bestWorker.id
85
+ }
86
+
87
+ return null
88
+ }
89
+
90
+ /**
91
+ * Attempt to steal work from another worker
92
+ */
93
+ steal(thiefId: string): ProofTask | null {
94
+ const thief = this.workers.get(thiefId)
95
+ if (!thief) return null
96
+
97
+ // Find victim with longest queue (at least 2 tasks to steal 1)
98
+ let victim: WorkerState | null = null
99
+ let longestQueue = 1 // Need at least 2 to steal
100
+
101
+ for (const worker of this.workers.values()) {
102
+ if (worker.id !== thiefId && worker.taskQueue.length > longestQueue) {
103
+ longestQueue = worker.taskQueue.length
104
+ victim = worker
105
+ }
106
+ }
107
+
108
+ if (victim && victim.taskQueue.length > 1) {
109
+ // Steal from the end of the queue (LIFO steal)
110
+ const stolenTask = victim.taskQueue.pop()!
111
+
112
+ // Record steal event
113
+ this.recordStealEvent({
114
+ timestamp: Date.now(),
115
+ thief: thiefId,
116
+ victim: victim.id,
117
+ taskId: stolenTask.id,
118
+ victimQueueLength: victim.taskQueue.length + 1, // Before steal
119
+ thiefQueueLength: thief.taskQueue.length,
120
+ })
121
+
122
+ return stolenTask
123
+ }
124
+
125
+ return null
126
+ }
127
+
128
+ /**
129
+ * Get stealing statistics for all workers
130
+ */
131
+ getStealingStats(): readonly WorkerStealingStats[] {
132
+ const stats: WorkerStealingStats[] = []
133
+
134
+ for (const worker of this.workers.values()) {
135
+ const tasksStolen = this.stealHistory.filter((e) => e.victim === worker.id).length
136
+ const tasksAcquired = this.stealHistory.filter((e) => e.thief === worker.id).length
137
+ const avgQueueLength = worker.taskQueue.length // Simplified
138
+
139
+ stats.push({
140
+ workerId: worker.id,
141
+ tasksStolen,
142
+ tasksAcquired,
143
+ averageQueueLength: avgQueueLength,
144
+ })
145
+ }
146
+
147
+ return stats
148
+ }
149
+
150
+ /**
151
+ * Get steal events history
152
+ */
153
+ getStealHistory(limit?: number): readonly WorkStealEvent[] {
154
+ if (limit) {
155
+ return this.stealHistory.slice(-limit)
156
+ }
157
+ return [...this.stealHistory]
158
+ }
159
+
160
+ /**
161
+ * Clear a worker's queue and return tasks
162
+ */
163
+ clearWorkerQueue(workerId: string): readonly ProofTask[] {
164
+ const worker = this.workers.get(workerId)
165
+ if (!worker) return []
166
+
167
+ const tasks = [...worker.taskQueue]
168
+ worker.taskQueue = []
169
+ return tasks
170
+ }
171
+
172
+ private recordStealEvent(event: WorkStealEvent): void {
173
+ this.stealHistory.push(event)
174
+
175
+ // Limit history size
176
+ if (this.stealHistory.length > this.maxHistorySize) {
177
+ this.stealHistory.shift()
178
+ }
179
+ }
180
+ }
181
+
182
+ // ─── Worker Pool Implementation ──────────────────────────────────────────────
183
+
184
+ /**
185
+ * Manages a pool of workers for parallel proof generation
186
+ */
187
+ export class WorkerPool implements IWorkerPool {
188
+ private readonly config: WorkerPoolConfig
189
+ private readonly workers = new Map<string, WorkerState>()
190
+ private readonly scheduler: WorkStealingScheduler
191
+ private readonly providerFactory: () => ComposableProofProvider
192
+
193
+ private running = true
194
+ private paused = false
195
+ private taskIdCounter = 0
196
+ private completedTasks = 0
197
+ private failedTasks = 0
198
+ private totalTasks = 0
199
+ private workSteals = 0
200
+ private peakMemoryUsage = 0
201
+ private startTime: number
202
+
203
+ private workStealingInterval: ReturnType<typeof setInterval> | null = null
204
+ private idleCheckInterval: ReturnType<typeof setInterval> | null = null
205
+
206
+ constructor(
207
+ config: Partial<WorkerPoolConfig>,
208
+ providerFactory: () => ComposableProofProvider
209
+ ) {
210
+ this.config = { ...DEFAULT_WORKER_POOL_CONFIG, ...config }
211
+ this.scheduler = new WorkStealingScheduler()
212
+ this.providerFactory = providerFactory
213
+ this.startTime = Date.now()
214
+
215
+ // Initialize minimum workers
216
+ this.initializeWorkers()
217
+
218
+ // Start work stealing if enabled
219
+ if (this.config.enableWorkStealing) {
220
+ this.startWorkStealing()
221
+ }
222
+
223
+ // Start idle worker cleanup
224
+ this.startIdleCleanup()
225
+ }
226
+
227
+ /**
228
+ * Submit a task to the pool
229
+ */
230
+ async submit(task: ProofTask, options?: TaskSubmitOptions): Promise<SingleProof> {
231
+ if (!this.running) {
232
+ throw new Error('Worker pool is not running')
233
+ }
234
+
235
+ this.totalTasks++
236
+
237
+ // Apply options
238
+ if (options?.priority) {
239
+ const t = task as { priority: typeof options.priority }
240
+ t.priority = options.priority
241
+ }
242
+ if (options?.maxRetries !== undefined) {
243
+ const t = task as { maxRetries: number }
244
+ t.maxRetries = options.maxRetries
245
+ }
246
+
247
+ return new Promise((resolve, reject) => {
248
+ const timeoutMs = options?.timeoutMs ?? 120000 // 2 minute default
249
+
250
+ // Setup timeout
251
+ const timeoutId = setTimeout(() => {
252
+ task.status = 'failed'
253
+ task.error = new Error(`Task ${task.id} timed out after ${timeoutMs}ms`)
254
+ this.failedTasks++
255
+ options?.onError?.(task, task.error)
256
+ reject(task.error)
257
+ }, timeoutMs)
258
+
259
+ // Execute task
260
+ this.executeTask(task)
261
+ .then((result) => {
262
+ clearTimeout(timeoutId)
263
+ task.status = 'completed'
264
+ task.result = result
265
+ task.completedAt = Date.now()
266
+ this.completedTasks++
267
+ options?.onComplete?.(task)
268
+ resolve(result)
269
+ })
270
+ .catch((error) => {
271
+ clearTimeout(timeoutId)
272
+ task.status = 'failed'
273
+ task.error = error instanceof Error ? error : new Error(String(error))
274
+ this.failedTasks++
275
+ options?.onError?.(task, task.error)
276
+ reject(task.error)
277
+ })
278
+ })
279
+ }
280
+
281
+ /**
282
+ * Get current pool statistics
283
+ */
284
+ getStats(): WorkerPoolStats {
285
+ let busyWorkers = 0
286
+ let idleWorkers = 0
287
+ let queuedTasks = 0
288
+ let memoryUsage = 0
289
+
290
+ for (const worker of this.workers.values()) {
291
+ if (worker.status === 'busy') {
292
+ busyWorkers++
293
+ } else if (worker.status === 'idle') {
294
+ idleWorkers++
295
+ }
296
+ queuedTasks += worker.taskQueue.length
297
+ memoryUsage += worker.memoryUsage
298
+ }
299
+
300
+ this.peakMemoryUsage = Math.max(this.peakMemoryUsage, memoryUsage)
301
+
302
+ const totalExecutionTime = Array.from(this.workers.values()).reduce(
303
+ (sum, w) => sum + w.totalExecutionTime,
304
+ 0
305
+ )
306
+ const averageTaskTime =
307
+ this.completedTasks > 0 ? totalExecutionTime / this.completedTasks : 0
308
+
309
+ return {
310
+ workerCount: this.workers.size,
311
+ busyWorkers,
312
+ idleWorkers,
313
+ queuedTasks,
314
+ completedTasks: this.completedTasks,
315
+ failedTasks: this.failedTasks,
316
+ totalTasks: this.totalTasks,
317
+ averageTaskTime,
318
+ workSteals: this.workSteals,
319
+ memoryUsage,
320
+ peakMemoryUsage: this.peakMemoryUsage,
321
+ uptime: Date.now() - this.startTime,
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Get information about all workers
327
+ */
328
+ getWorkers(): readonly WorkerInfo[] {
329
+ return Array.from(this.workers.values()).map((w) => ({
330
+ id: w.id,
331
+ status: w.status,
332
+ currentTask: w.currentTask?.id,
333
+ tasksCompleted: w.tasksCompleted,
334
+ totalExecutionTime: w.totalExecutionTime,
335
+ averageTaskTime: w.tasksCompleted > 0 ? w.totalExecutionTime / w.tasksCompleted : 0,
336
+ memoryUsage: w.memoryUsage,
337
+ createdAt: w.createdAt,
338
+ lastActiveAt: w.lastActiveAt,
339
+ }))
340
+ }
341
+
342
+ /**
343
+ * Scale pool to target worker count
344
+ */
345
+ async scale(targetWorkers: number): Promise<void> {
346
+ const clamped = Math.max(
347
+ this.config.minWorkers,
348
+ Math.min(this.config.maxWorkers, targetWorkers)
349
+ )
350
+
351
+ const currentCount = this.workers.size
352
+
353
+ if (clamped > currentCount) {
354
+ // Add workers
355
+ for (let i = 0; i < clamped - currentCount; i++) {
356
+ this.createWorker()
357
+ }
358
+ } else if (clamped < currentCount) {
359
+ // Remove idle workers first
360
+ const workersToRemove = currentCount - clamped
361
+ let removed = 0
362
+
363
+ for (const [workerId, worker] of this.workers) {
364
+ if (removed >= workersToRemove) break
365
+ if (worker.status === 'idle') {
366
+ await this.terminateWorker(workerId)
367
+ removed++
368
+ }
369
+ }
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Pause task execution
375
+ */
376
+ pause(): void {
377
+ this.paused = true
378
+ }
379
+
380
+ /**
381
+ * Resume task execution
382
+ */
383
+ resume(): void {
384
+ this.paused = false
385
+ // Process any queued tasks
386
+ this.processQueues()
387
+ }
388
+
389
+ /**
390
+ * Shutdown the pool
391
+ */
392
+ async shutdown(): Promise<void> {
393
+ this.running = false
394
+
395
+ // Stop intervals
396
+ if (this.workStealingInterval) {
397
+ clearInterval(this.workStealingInterval)
398
+ }
399
+ if (this.idleCheckInterval) {
400
+ clearInterval(this.idleCheckInterval)
401
+ }
402
+
403
+ // Terminate all workers
404
+ const terminationPromises: Promise<void>[] = []
405
+ for (const workerId of this.workers.keys()) {
406
+ terminationPromises.push(this.terminateWorker(workerId))
407
+ }
408
+
409
+ await Promise.all(terminationPromises)
410
+ }
411
+
412
+ /**
413
+ * Check if pool is running
414
+ */
415
+ isRunning(): boolean {
416
+ return this.running
417
+ }
418
+
419
+ /**
420
+ * Get the work stealing scheduler
421
+ */
422
+ getScheduler(): IWorkStealingScheduler {
423
+ return this.scheduler
424
+ }
425
+
426
+ // ─── Private Methods ─────────────────────────────────────────────────────────
427
+
428
+ private initializeWorkers(): void {
429
+ for (let i = 0; i < this.config.minWorkers; i++) {
430
+ this.createWorker()
431
+ }
432
+ }
433
+
434
+ private createWorker(): WorkerState {
435
+ const id = `worker-${++this.taskIdCounter}`
436
+ const worker: WorkerState = {
437
+ id,
438
+ status: 'idle',
439
+ currentTask: null,
440
+ taskQueue: [],
441
+ tasksCompleted: 0,
442
+ totalExecutionTime: 0,
443
+ memoryUsage: 0,
444
+ createdAt: Date.now(),
445
+ lastActiveAt: Date.now(),
446
+ }
447
+
448
+ this.workers.set(id, worker)
449
+ this.scheduler.registerWorker(worker)
450
+
451
+ return worker
452
+ }
453
+
454
+ private async terminateWorker(workerId: string): Promise<void> {
455
+ const worker = this.workers.get(workerId)
456
+ if (!worker) return
457
+
458
+ worker.status = 'terminating'
459
+
460
+ // Redistribute queued tasks
461
+ const tasks = this.scheduler.clearWorkerQueue(workerId)
462
+ for (const task of tasks) {
463
+ this.scheduler.assign(task)
464
+ }
465
+
466
+ worker.status = 'terminated'
467
+ this.scheduler.unregisterWorker(workerId)
468
+ this.workers.delete(workerId)
469
+ }
470
+
471
+ private async executeTask(task: ProofTask): Promise<SingleProof> {
472
+ // Wait if paused
473
+ while (this.paused) {
474
+ await new Promise((resolve) => setTimeout(resolve, 100))
475
+ }
476
+
477
+ // Find available worker or create one
478
+ let worker = this.findIdleWorker()
479
+ if (!worker && this.workers.size < this.config.maxWorkers) {
480
+ worker = this.createWorker()
481
+ }
482
+
483
+ if (!worker) {
484
+ // Queue the task
485
+ task.status = 'queued'
486
+ const assignedWorkerId = this.scheduler.assign(task)
487
+ if (!assignedWorkerId) {
488
+ throw new Error('No workers available to execute task')
489
+ }
490
+
491
+ // Wait for task to be processed
492
+ return new Promise((resolve, reject) => {
493
+ const checkInterval = setInterval(() => {
494
+ if (task.status === 'completed' && task.result) {
495
+ clearInterval(checkInterval)
496
+ resolve(task.result)
497
+ } else if (task.status === 'failed') {
498
+ clearInterval(checkInterval)
499
+ reject(task.error ?? new Error('Task failed'))
500
+ }
501
+ }, 50)
502
+ })
503
+ }
504
+
505
+ // Execute immediately
506
+ return this.runTaskOnWorker(worker, task)
507
+ }
508
+
509
+ private async runTaskOnWorker(worker: WorkerState, task: ProofTask): Promise<SingleProof> {
510
+ worker.status = 'busy'
511
+ worker.currentTask = task
512
+ worker.lastActiveAt = Date.now()
513
+ task.status = 'running'
514
+ task.startedAt = Date.now()
515
+ task.workerId = worker.id
516
+
517
+ try {
518
+ // Get a provider instance
519
+ const provider = this.providerFactory()
520
+
521
+ // Generate the proof
522
+ const startTime = Date.now()
523
+ const result = await provider.generateProof({
524
+ circuitId: task.node.circuitId,
525
+ privateInputs: task.node.privateInputs,
526
+ publicInputs: task.node.publicInputs,
527
+ })
528
+
529
+ const executionTime = Date.now() - startTime
530
+ worker.totalExecutionTime += executionTime
531
+ worker.tasksCompleted++
532
+ worker.memoryUsage = Math.max(worker.memoryUsage, task.node.estimatedMemory)
533
+
534
+ // Mark worker as idle and process queue
535
+ worker.status = 'idle'
536
+ worker.currentTask = null
537
+
538
+ // Check for successful proof generation
539
+ if (!result.success || !result.proof) {
540
+ throw new Error(result.error ?? 'Proof generation failed')
541
+ }
542
+
543
+ // Process next task in queue
544
+ this.processWorkerQueue(worker)
545
+
546
+ return result.proof
547
+ } catch (error) {
548
+ worker.status = 'idle'
549
+ worker.currentTask = null
550
+
551
+ // Retry if allowed
552
+ if (task.retryCount < task.maxRetries) {
553
+ task.retryCount++
554
+ task.status = 'queued'
555
+ return this.executeTask(task)
556
+ }
557
+
558
+ throw error
559
+ }
560
+ }
561
+
562
+ private findIdleWorker(): WorkerState | null {
563
+ for (const worker of this.workers.values()) {
564
+ if (worker.status === 'idle') {
565
+ return worker
566
+ }
567
+ }
568
+ return null
569
+ }
570
+
571
+ private processQueues(): void {
572
+ for (const worker of this.workers.values()) {
573
+ if (worker.status === 'idle') {
574
+ this.processWorkerQueue(worker)
575
+ }
576
+ }
577
+ }
578
+
579
+ private processWorkerQueue(worker: WorkerState): void {
580
+ if (worker.taskQueue.length === 0 || this.paused) {
581
+ return
582
+ }
583
+
584
+ const nextTask = worker.taskQueue.shift()
585
+ if (nextTask) {
586
+ this.runTaskOnWorker(worker, nextTask).catch(() => {
587
+ // Error handled in runTaskOnWorker
588
+ })
589
+ }
590
+ }
591
+
592
+ private startWorkStealing(): void {
593
+ this.workStealingInterval = setInterval(() => {
594
+ if (this.paused) return
595
+
596
+ // Find idle workers
597
+ for (const worker of this.workers.values()) {
598
+ if (worker.status === 'idle' && worker.taskQueue.length === 0) {
599
+ const stolenTask = this.scheduler.steal(worker.id)
600
+ if (stolenTask) {
601
+ this.workSteals++
602
+ this.runTaskOnWorker(worker, stolenTask).catch(() => {
603
+ // Error handled in runTaskOnWorker
604
+ })
605
+ }
606
+ }
607
+ }
608
+ }, this.config.workStealingIntervalMs)
609
+ }
610
+
611
+ private startIdleCleanup(): void {
612
+ this.idleCheckInterval = setInterval(() => {
613
+ const now = Date.now()
614
+
615
+ for (const [workerId, worker] of this.workers) {
616
+ // Don't remove workers below minimum
617
+ if (this.workers.size <= this.config.minWorkers) {
618
+ break
619
+ }
620
+
621
+ // Check if worker has been idle too long
622
+ if (
623
+ worker.status === 'idle' &&
624
+ worker.taskQueue.length === 0 &&
625
+ now - worker.lastActiveAt > this.config.idleTimeoutMs
626
+ ) {
627
+ this.terminateWorker(workerId).catch(() => {
628
+ // Ignore termination errors
629
+ })
630
+ }
631
+ }
632
+ }, this.config.idleTimeoutMs / 2)
633
+ }
634
+ }
635
+
636
+ /**
637
+ * Create a worker pool instance
638
+ */
639
+ export function createWorkerPool(
640
+ config: Partial<WorkerPoolConfig>,
641
+ providerFactory: () => ComposableProofProvider
642
+ ): IWorkerPool {
643
+ return new WorkerPool(config, providerFactory)
644
+ }