@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.
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +48874 -18336
- package/dist/browser.mjs +674 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/chunk-YWGJ77A2.mjs +33806 -0
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/index-DXh2IGkz.d.ts +24681 -0
- package/dist/index-DeE1ZzA4.d.mts +24681 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48676 -17318
- package/dist/index.mjs +583 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +276 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +201 -0
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +402 -0
- package/src/chains/solana/providers/index.ts +85 -0
- package/src/chains/solana/providers/interface.ts +221 -0
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +790 -0
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +170 -73
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +77 -7
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +37 -0
- package/src/compliance/range-sas.ts +956 -0
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +785 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +336 -0
- package/src/privacy-backends/interface.ts +906 -0
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +456 -0
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +690 -0
- package/src/privacy-backends/router.ts +626 -0
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +256 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +111 -30
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-5EMCTPTS.mjs +0 -46
- 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
|
+
}
|