@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,1004 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy Proof Generation
|
|
3
|
+
*
|
|
4
|
+
* @module proofs/lazy
|
|
5
|
+
* @description Deferred proof generation with cancellation and priority queue
|
|
6
|
+
*
|
|
7
|
+
* M20-14: Add lazy proof generation support (#319)
|
|
8
|
+
*
|
|
9
|
+
* ## Overview
|
|
10
|
+
*
|
|
11
|
+
* Lazy proofs defer computation until absolutely necessary, improving:
|
|
12
|
+
* - Perceived performance (don't block on proof generation)
|
|
13
|
+
* - Resource usage (only generate proofs that are actually needed)
|
|
14
|
+
* - User experience (can cancel unnecessary proof generation)
|
|
15
|
+
*
|
|
16
|
+
* ## Usage
|
|
17
|
+
*
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { LazyProof, ProofGenerationQueue } from '@sip-protocol/sdk'
|
|
20
|
+
*
|
|
21
|
+
* // Create a lazy proof
|
|
22
|
+
* const lazy = new LazyProof(async (signal) => {
|
|
23
|
+
* return await provider.generateProof(inputs, signal)
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* // Proof is NOT generated yet
|
|
27
|
+
* console.log(lazy.status) // 'pending'
|
|
28
|
+
*
|
|
29
|
+
* // Trigger generation when needed
|
|
30
|
+
* const proof = await lazy.resolve()
|
|
31
|
+
*
|
|
32
|
+
* // Or cancel if no longer needed
|
|
33
|
+
* lazy.cancel()
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import type { SingleProof, ProofSystem } from '@sip-protocol/types'
|
|
38
|
+
|
|
39
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Status of a lazy proof
|
|
43
|
+
*/
|
|
44
|
+
export type LazyProofStatus =
|
|
45
|
+
| 'pending' // Not yet started
|
|
46
|
+
| 'generating' // Currently being generated
|
|
47
|
+
| 'resolved' // Successfully generated
|
|
48
|
+
| 'cancelled' // Generation was cancelled
|
|
49
|
+
| 'failed' // Generation failed
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Trigger for automatic proof generation
|
|
53
|
+
*/
|
|
54
|
+
export type ProofTrigger =
|
|
55
|
+
| 'manual' // Only on explicit resolve()
|
|
56
|
+
| 'on-verify' // When verification is requested
|
|
57
|
+
| 'on-serialize' // When serialization is requested
|
|
58
|
+
| 'immediate' // Start immediately (eager)
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Priority level for proof generation
|
|
62
|
+
*/
|
|
63
|
+
export type ProofPriority = 'low' | 'normal' | 'high' | 'critical'
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Configuration for lazy proof
|
|
67
|
+
*/
|
|
68
|
+
export interface LazyProofConfig {
|
|
69
|
+
/** When to trigger proof generation */
|
|
70
|
+
readonly trigger: ProofTrigger
|
|
71
|
+
/** Priority in the generation queue */
|
|
72
|
+
readonly priority: ProofPriority
|
|
73
|
+
/** Timeout in milliseconds (0 = no timeout) */
|
|
74
|
+
readonly timeoutMs: number
|
|
75
|
+
/** Retry attempts on failure */
|
|
76
|
+
readonly maxRetries: number
|
|
77
|
+
/** Delay between retries in milliseconds */
|
|
78
|
+
readonly retryDelayMs: number
|
|
79
|
+
/** Enable speculative prefetching */
|
|
80
|
+
readonly prefetch: boolean
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Default lazy proof configuration
|
|
85
|
+
*/
|
|
86
|
+
export const DEFAULT_LAZY_CONFIG: LazyProofConfig = {
|
|
87
|
+
trigger: 'manual',
|
|
88
|
+
priority: 'normal',
|
|
89
|
+
timeoutMs: 60000, // 1 minute
|
|
90
|
+
maxRetries: 2,
|
|
91
|
+
retryDelayMs: 1000,
|
|
92
|
+
prefetch: false,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Proof generator function type
|
|
97
|
+
*/
|
|
98
|
+
export type ProofGenerator<T = SingleProof> = (
|
|
99
|
+
signal: AbortSignal
|
|
100
|
+
) => Promise<T>
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Event types for lazy proof
|
|
104
|
+
*/
|
|
105
|
+
export type LazyProofEventType =
|
|
106
|
+
| 'start'
|
|
107
|
+
| 'progress'
|
|
108
|
+
| 'complete'
|
|
109
|
+
| 'cancel'
|
|
110
|
+
| 'error'
|
|
111
|
+
| 'retry'
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Lazy proof event
|
|
115
|
+
*/
|
|
116
|
+
export interface LazyProofEvent {
|
|
117
|
+
readonly type: LazyProofEventType
|
|
118
|
+
readonly timestamp: number
|
|
119
|
+
readonly data?: {
|
|
120
|
+
readonly progress?: number
|
|
121
|
+
readonly error?: Error
|
|
122
|
+
readonly attempt?: number
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Event listener for lazy proof
|
|
128
|
+
*/
|
|
129
|
+
export type LazyProofEventListener = (event: LazyProofEvent) => void
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Serialized lazy proof (for persistence)
|
|
133
|
+
*/
|
|
134
|
+
export interface SerializedLazyProof<T = SingleProof> {
|
|
135
|
+
readonly status: LazyProofStatus
|
|
136
|
+
readonly proof?: T
|
|
137
|
+
readonly error?: string
|
|
138
|
+
readonly config: LazyProofConfig
|
|
139
|
+
readonly metadata?: {
|
|
140
|
+
readonly system?: ProofSystem
|
|
141
|
+
readonly circuitId?: string
|
|
142
|
+
readonly createdAt: number
|
|
143
|
+
readonly resolvedAt?: number
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─── LazyProof Class ──────────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A lazy proof that defers generation until needed
|
|
151
|
+
*/
|
|
152
|
+
export class LazyProof<T = SingleProof> {
|
|
153
|
+
private _status: LazyProofStatus = 'pending'
|
|
154
|
+
private _proof: T | null = null
|
|
155
|
+
private _error: Error | null = null
|
|
156
|
+
private _promise: Promise<T> | null = null
|
|
157
|
+
private _abortController: AbortController | null = null
|
|
158
|
+
private _retryCount = 0
|
|
159
|
+
private _createdAt = Date.now()
|
|
160
|
+
private _resolvedAt: number | null = null
|
|
161
|
+
private readonly _listeners = new Set<LazyProofEventListener>()
|
|
162
|
+
|
|
163
|
+
readonly config: LazyProofConfig
|
|
164
|
+
|
|
165
|
+
constructor(
|
|
166
|
+
private readonly generator: ProofGenerator<T>,
|
|
167
|
+
config: Partial<LazyProofConfig> = {},
|
|
168
|
+
private readonly metadata?: {
|
|
169
|
+
system?: ProofSystem
|
|
170
|
+
circuitId?: string
|
|
171
|
+
}
|
|
172
|
+
) {
|
|
173
|
+
this.config = { ...DEFAULT_LAZY_CONFIG, ...config }
|
|
174
|
+
// Start immediately if configured
|
|
175
|
+
if (this.config.trigger === 'immediate') {
|
|
176
|
+
this.resolve().catch(() => {})
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get the current status
|
|
182
|
+
*/
|
|
183
|
+
get status(): LazyProofStatus {
|
|
184
|
+
return this._status
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check if the proof is resolved
|
|
189
|
+
*/
|
|
190
|
+
get isResolved(): boolean {
|
|
191
|
+
return this._status === 'resolved'
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Check if generation is in progress
|
|
196
|
+
*/
|
|
197
|
+
get isGenerating(): boolean {
|
|
198
|
+
return this._status === 'generating'
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Check if cancelled
|
|
203
|
+
*/
|
|
204
|
+
get isCancelled(): boolean {
|
|
205
|
+
return this._status === 'cancelled'
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Check if failed
|
|
210
|
+
*/
|
|
211
|
+
get isFailed(): boolean {
|
|
212
|
+
return this._status === 'failed'
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get the proof (throws if not resolved)
|
|
217
|
+
*/
|
|
218
|
+
get proof(): T {
|
|
219
|
+
if (!this._proof) {
|
|
220
|
+
throw new LazyProofError(
|
|
221
|
+
'Proof not yet resolved. Call resolve() first.',
|
|
222
|
+
'NOT_RESOLVED'
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
return this._proof
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get the proof if available (doesn't throw)
|
|
230
|
+
*/
|
|
231
|
+
get proofOrNull(): T | null {
|
|
232
|
+
return this._proof
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the error if failed
|
|
237
|
+
*/
|
|
238
|
+
get error(): Error | null {
|
|
239
|
+
return this._error
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Resolve (generate) the proof
|
|
244
|
+
*/
|
|
245
|
+
async resolve(): Promise<T> {
|
|
246
|
+
// Already resolved
|
|
247
|
+
if (this._status === 'resolved' && this._proof) {
|
|
248
|
+
return this._proof
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Already generating - return existing promise
|
|
252
|
+
if (this._status === 'generating' && this._promise) {
|
|
253
|
+
return this._promise
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Cannot resolve cancelled proof
|
|
257
|
+
if (this._status === 'cancelled') {
|
|
258
|
+
throw new LazyProofError('Proof generation was cancelled', 'CANCELLED')
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Start generation
|
|
262
|
+
this._promise = this._generate()
|
|
263
|
+
return this._promise
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Cancel proof generation
|
|
268
|
+
*/
|
|
269
|
+
cancel(): boolean {
|
|
270
|
+
if (this._status === 'resolved' || this._status === 'cancelled') {
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this._status = 'cancelled'
|
|
275
|
+
this._abortController?.abort()
|
|
276
|
+
this._emit({ type: 'cancel', timestamp: Date.now() })
|
|
277
|
+
return true
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Reset to pending state (allows re-generation)
|
|
282
|
+
*/
|
|
283
|
+
reset(): void {
|
|
284
|
+
if (this._status === 'generating') {
|
|
285
|
+
this.cancel()
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this._status = 'pending'
|
|
289
|
+
this._proof = null
|
|
290
|
+
this._error = null
|
|
291
|
+
this._promise = null
|
|
292
|
+
this._retryCount = 0
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Add an event listener
|
|
297
|
+
*/
|
|
298
|
+
addEventListener(listener: LazyProofEventListener): void {
|
|
299
|
+
this._listeners.add(listener)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Remove an event listener
|
|
304
|
+
*/
|
|
305
|
+
removeEventListener(listener: LazyProofEventListener): void {
|
|
306
|
+
this._listeners.delete(listener)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Serialize the lazy proof
|
|
311
|
+
*/
|
|
312
|
+
serialize(): SerializedLazyProof<T> {
|
|
313
|
+
// Trigger generation if configured
|
|
314
|
+
if (this.config.trigger === 'on-serialize' && this._status === 'pending') {
|
|
315
|
+
this.resolve().catch(() => {})
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
status: this._status,
|
|
320
|
+
proof: this._proof ?? undefined,
|
|
321
|
+
error: this._error?.message,
|
|
322
|
+
config: this.config,
|
|
323
|
+
metadata: {
|
|
324
|
+
system: this.metadata?.system,
|
|
325
|
+
circuitId: this.metadata?.circuitId,
|
|
326
|
+
createdAt: this._createdAt,
|
|
327
|
+
resolvedAt: this._resolvedAt ?? undefined,
|
|
328
|
+
},
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Create from serialized state
|
|
334
|
+
*/
|
|
335
|
+
static deserialize<T = SingleProof>(
|
|
336
|
+
data: SerializedLazyProof<T>,
|
|
337
|
+
generator: ProofGenerator<T>
|
|
338
|
+
): LazyProof<T> {
|
|
339
|
+
const lazy = new LazyProof<T>(generator, data.config, {
|
|
340
|
+
system: data.metadata?.system,
|
|
341
|
+
circuitId: data.metadata?.circuitId,
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
if (data.status === 'resolved' && data.proof) {
|
|
345
|
+
lazy._status = 'resolved'
|
|
346
|
+
lazy._proof = data.proof
|
|
347
|
+
lazy._resolvedAt = data.metadata?.resolvedAt ?? null
|
|
348
|
+
} else if (data.status === 'failed' && data.error) {
|
|
349
|
+
lazy._status = 'failed'
|
|
350
|
+
lazy._error = new Error(data.error)
|
|
351
|
+
} else if (data.status === 'cancelled') {
|
|
352
|
+
lazy._status = 'cancelled'
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return lazy
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// ─── Private Methods ────────────────────────────────────────────────────────
|
|
359
|
+
|
|
360
|
+
private async _generate(): Promise<T> {
|
|
361
|
+
this._status = 'generating'
|
|
362
|
+
this._abortController = new AbortController()
|
|
363
|
+
this._emit({ type: 'start', timestamp: Date.now() })
|
|
364
|
+
|
|
365
|
+
const { timeoutMs, maxRetries, retryDelayMs } = this.config
|
|
366
|
+
|
|
367
|
+
while (this._retryCount <= maxRetries) {
|
|
368
|
+
try {
|
|
369
|
+
// Create timeout if configured
|
|
370
|
+
const timeoutId = timeoutMs > 0
|
|
371
|
+
? setTimeout(() => this._abortController?.abort(), timeoutMs)
|
|
372
|
+
: null
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
const proof = await this.generator(this._abortController.signal)
|
|
376
|
+
|
|
377
|
+
// Success!
|
|
378
|
+
this._proof = proof
|
|
379
|
+
this._status = 'resolved'
|
|
380
|
+
this._resolvedAt = Date.now()
|
|
381
|
+
this._emit({ type: 'complete', timestamp: Date.now() })
|
|
382
|
+
return proof
|
|
383
|
+
} finally {
|
|
384
|
+
if (timeoutId) clearTimeout(timeoutId)
|
|
385
|
+
}
|
|
386
|
+
} catch (err) {
|
|
387
|
+
// Check if cancelled (cast needed - cancel() can be called concurrently)
|
|
388
|
+
if (this._abortController.signal.aborted) {
|
|
389
|
+
if ((this._status as LazyProofStatus) === 'cancelled') {
|
|
390
|
+
throw new LazyProofError('Proof generation was cancelled', 'CANCELLED')
|
|
391
|
+
}
|
|
392
|
+
throw new LazyProofError('Proof generation timed out', 'TIMEOUT')
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Retry logic
|
|
396
|
+
this._retryCount++
|
|
397
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
398
|
+
|
|
399
|
+
if (this._retryCount <= maxRetries) {
|
|
400
|
+
this._emit({
|
|
401
|
+
type: 'retry',
|
|
402
|
+
timestamp: Date.now(),
|
|
403
|
+
data: { attempt: this._retryCount, error },
|
|
404
|
+
})
|
|
405
|
+
await this._delay(retryDelayMs)
|
|
406
|
+
// Create new abort controller for retry
|
|
407
|
+
this._abortController = new AbortController()
|
|
408
|
+
} else {
|
|
409
|
+
// Max retries exceeded
|
|
410
|
+
this._status = 'failed'
|
|
411
|
+
this._error = error
|
|
412
|
+
this._emit({ type: 'error', timestamp: Date.now(), data: { error } })
|
|
413
|
+
throw error
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Should never reach here
|
|
419
|
+
throw new LazyProofError('Unexpected error in proof generation', 'INTERNAL')
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private _emit(event: LazyProofEvent): void {
|
|
423
|
+
for (const listener of this._listeners) {
|
|
424
|
+
try {
|
|
425
|
+
listener(event)
|
|
426
|
+
} catch {
|
|
427
|
+
// Ignore listener errors
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
private _delay(ms: number): Promise<void> {
|
|
433
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ─── Proof Generation Queue ───────────────────────────────────────────────────
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Queue item for proof generation
|
|
441
|
+
*/
|
|
442
|
+
interface QueueItem<T = SingleProof> {
|
|
443
|
+
readonly id: string
|
|
444
|
+
readonly lazy: LazyProof<T>
|
|
445
|
+
readonly priority: ProofPriority
|
|
446
|
+
readonly addedAt: number
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Priority values for sorting
|
|
451
|
+
*/
|
|
452
|
+
const PRIORITY_VALUES: Record<ProofPriority, number> = {
|
|
453
|
+
critical: 4,
|
|
454
|
+
high: 3,
|
|
455
|
+
normal: 2,
|
|
456
|
+
low: 1,
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Configuration for proof generation queue
|
|
461
|
+
*/
|
|
462
|
+
export interface ProofQueueConfig {
|
|
463
|
+
/** Maximum concurrent proof generations */
|
|
464
|
+
readonly maxConcurrent: number
|
|
465
|
+
/** Maximum queue size (0 = unlimited) */
|
|
466
|
+
readonly maxQueueSize: number
|
|
467
|
+
/** Enable automatic processing */
|
|
468
|
+
readonly autoProcess: boolean
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Default queue configuration
|
|
473
|
+
*/
|
|
474
|
+
export const DEFAULT_QUEUE_CONFIG: ProofQueueConfig = {
|
|
475
|
+
maxConcurrent: 2,
|
|
476
|
+
maxQueueSize: 100,
|
|
477
|
+
autoProcess: true,
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Queue statistics
|
|
482
|
+
*/
|
|
483
|
+
export interface QueueStats {
|
|
484
|
+
readonly queued: number
|
|
485
|
+
readonly processing: number
|
|
486
|
+
readonly completed: number
|
|
487
|
+
readonly failed: number
|
|
488
|
+
readonly cancelled: number
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Priority queue for proof generation
|
|
493
|
+
*/
|
|
494
|
+
export class ProofGenerationQueue<T = SingleProof> {
|
|
495
|
+
private readonly queue: QueueItem<T>[] = []
|
|
496
|
+
private readonly processing = new Map<string, LazyProof<T>>()
|
|
497
|
+
private readonly config: ProofQueueConfig
|
|
498
|
+
private _completed = 0
|
|
499
|
+
private _failed = 0
|
|
500
|
+
private _cancelled = 0
|
|
501
|
+
private _idCounter = 0
|
|
502
|
+
private _isProcessing = false
|
|
503
|
+
|
|
504
|
+
constructor(config: Partial<ProofQueueConfig> = {}) {
|
|
505
|
+
this.config = { ...DEFAULT_QUEUE_CONFIG, ...config }
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Add a lazy proof to the queue
|
|
510
|
+
*/
|
|
511
|
+
enqueue(lazy: LazyProof<T>, priority?: ProofPriority): string {
|
|
512
|
+
if (
|
|
513
|
+
this.config.maxQueueSize > 0 &&
|
|
514
|
+
this.queue.length >= this.config.maxQueueSize
|
|
515
|
+
) {
|
|
516
|
+
throw new LazyProofError('Queue is full', 'QUEUE_FULL')
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const id = `proof-${++this._idCounter}`
|
|
520
|
+
const item: QueueItem<T> = {
|
|
521
|
+
id,
|
|
522
|
+
lazy,
|
|
523
|
+
priority: priority ?? lazy.config.priority,
|
|
524
|
+
addedAt: Date.now(),
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Insert in priority order
|
|
528
|
+
const insertIndex = this.queue.findIndex(
|
|
529
|
+
(q) => PRIORITY_VALUES[q.priority] < PRIORITY_VALUES[item.priority]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
if (insertIndex === -1) {
|
|
533
|
+
this.queue.push(item)
|
|
534
|
+
} else {
|
|
535
|
+
this.queue.splice(insertIndex, 0, item)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Auto-process if enabled
|
|
539
|
+
if (this.config.autoProcess) {
|
|
540
|
+
this._processNext()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return id
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Remove a proof from the queue
|
|
548
|
+
*/
|
|
549
|
+
dequeue(id: string): boolean {
|
|
550
|
+
const index = this.queue.findIndex((q) => q.id === id)
|
|
551
|
+
if (index !== -1) {
|
|
552
|
+
const [item] = this.queue.splice(index, 1)
|
|
553
|
+
item.lazy.cancel()
|
|
554
|
+
this._cancelled++
|
|
555
|
+
return true
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Check if currently processing
|
|
559
|
+
const processing = this.processing.get(id)
|
|
560
|
+
if (processing) {
|
|
561
|
+
processing.cancel()
|
|
562
|
+
this.processing.delete(id)
|
|
563
|
+
this._cancelled++
|
|
564
|
+
return true
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return false
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Process the queue manually
|
|
572
|
+
*/
|
|
573
|
+
async process(): Promise<void> {
|
|
574
|
+
if (this._isProcessing) return
|
|
575
|
+
|
|
576
|
+
this._isProcessing = true
|
|
577
|
+
|
|
578
|
+
try {
|
|
579
|
+
while (this.queue.length > 0 || this.processing.size > 0) {
|
|
580
|
+
await this._processNext()
|
|
581
|
+
// Small delay to prevent tight loop
|
|
582
|
+
await new Promise((r) => setTimeout(r, 10))
|
|
583
|
+
}
|
|
584
|
+
} finally {
|
|
585
|
+
this._isProcessing = false
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Cancel all pending and processing proofs
|
|
591
|
+
*/
|
|
592
|
+
cancelAll(): number {
|
|
593
|
+
let cancelled = 0
|
|
594
|
+
|
|
595
|
+
// Cancel queued
|
|
596
|
+
for (const item of this.queue) {
|
|
597
|
+
item.lazy.cancel()
|
|
598
|
+
cancelled++
|
|
599
|
+
}
|
|
600
|
+
this.queue.length = 0
|
|
601
|
+
|
|
602
|
+
// Cancel processing
|
|
603
|
+
for (const [id, lazy] of this.processing) {
|
|
604
|
+
lazy.cancel()
|
|
605
|
+
this.processing.delete(id)
|
|
606
|
+
cancelled++
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
this._cancelled += cancelled
|
|
610
|
+
return cancelled
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Get queue statistics
|
|
615
|
+
*/
|
|
616
|
+
getStats(): QueueStats {
|
|
617
|
+
return {
|
|
618
|
+
queued: this.queue.length,
|
|
619
|
+
processing: this.processing.size,
|
|
620
|
+
completed: this._completed,
|
|
621
|
+
failed: this._failed,
|
|
622
|
+
cancelled: this._cancelled,
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Get the current queue size
|
|
628
|
+
*/
|
|
629
|
+
get size(): number {
|
|
630
|
+
return this.queue.length + this.processing.size
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Check if queue is empty
|
|
635
|
+
*/
|
|
636
|
+
get isEmpty(): boolean {
|
|
637
|
+
return this.queue.length === 0 && this.processing.size === 0
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// ─── Private Methods ────────────────────────────────────────────────────────
|
|
641
|
+
|
|
642
|
+
private async _processNext(): Promise<void> {
|
|
643
|
+
// Check if we can process more
|
|
644
|
+
if (this.processing.size >= this.config.maxConcurrent) {
|
|
645
|
+
return
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Get next item
|
|
649
|
+
const item = this.queue.shift()
|
|
650
|
+
if (!item) return
|
|
651
|
+
|
|
652
|
+
// Start processing
|
|
653
|
+
this.processing.set(item.id, item.lazy)
|
|
654
|
+
|
|
655
|
+
try {
|
|
656
|
+
await item.lazy.resolve()
|
|
657
|
+
this._completed++
|
|
658
|
+
} catch {
|
|
659
|
+
if (item.lazy.isCancelled) {
|
|
660
|
+
this._cancelled++
|
|
661
|
+
} else {
|
|
662
|
+
this._failed++
|
|
663
|
+
}
|
|
664
|
+
} finally {
|
|
665
|
+
this.processing.delete(item.id)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Process next if auto-process enabled
|
|
669
|
+
if (this.config.autoProcess && this.queue.length > 0) {
|
|
670
|
+
this._processNext()
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// ─── Lazy Verification Key Loading ────────────────────────────────────────────
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* A lazy-loaded verification key
|
|
679
|
+
*/
|
|
680
|
+
export class LazyVerificationKey {
|
|
681
|
+
private _vk: string | null = null
|
|
682
|
+
private _promise: Promise<string> | null = null
|
|
683
|
+
private _status: 'pending' | 'loading' | 'loaded' | 'failed' = 'pending'
|
|
684
|
+
|
|
685
|
+
constructor(
|
|
686
|
+
private readonly loader: () => Promise<string>,
|
|
687
|
+
private readonly _system: ProofSystem,
|
|
688
|
+
private readonly _circuitId: string
|
|
689
|
+
) {}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Get the proof system this key belongs to
|
|
693
|
+
*/
|
|
694
|
+
get system(): ProofSystem {
|
|
695
|
+
return this._system
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Get the circuit ID
|
|
700
|
+
*/
|
|
701
|
+
get circuitId(): string {
|
|
702
|
+
return this._circuitId
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Get the verification key (loads if necessary)
|
|
707
|
+
*/
|
|
708
|
+
async get(): Promise<string> {
|
|
709
|
+
if (this._vk) return this._vk
|
|
710
|
+
|
|
711
|
+
if (this._promise) return this._promise
|
|
712
|
+
|
|
713
|
+
this._status = 'loading'
|
|
714
|
+
this._promise = this._load()
|
|
715
|
+
return this._promise
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Get the verification key synchronously (null if not loaded)
|
|
720
|
+
*/
|
|
721
|
+
getSync(): string | null {
|
|
722
|
+
return this._vk
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Check if loaded
|
|
727
|
+
*/
|
|
728
|
+
get isLoaded(): boolean {
|
|
729
|
+
return this._status === 'loaded'
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Preload the verification key
|
|
734
|
+
*/
|
|
735
|
+
preload(): void {
|
|
736
|
+
if (this._status === 'pending') {
|
|
737
|
+
this.get().catch(() => {})
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
private async _load(): Promise<string> {
|
|
742
|
+
try {
|
|
743
|
+
this._vk = await this.loader()
|
|
744
|
+
this._status = 'loaded'
|
|
745
|
+
return this._vk
|
|
746
|
+
} catch (err) {
|
|
747
|
+
this._status = 'failed'
|
|
748
|
+
throw err
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Registry for lazy verification keys
|
|
755
|
+
*/
|
|
756
|
+
export class VerificationKeyRegistry {
|
|
757
|
+
private readonly keys = new Map<string, LazyVerificationKey>()
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Register a verification key loader
|
|
761
|
+
*/
|
|
762
|
+
register(
|
|
763
|
+
system: ProofSystem,
|
|
764
|
+
circuitId: string,
|
|
765
|
+
loader: () => Promise<string>
|
|
766
|
+
): void {
|
|
767
|
+
const key = this._makeKey(system, circuitId)
|
|
768
|
+
this.keys.set(key, new LazyVerificationKey(loader, system, circuitId))
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Get a verification key
|
|
773
|
+
*/
|
|
774
|
+
async get(system: ProofSystem, circuitId: string): Promise<string> {
|
|
775
|
+
const key = this._makeKey(system, circuitId)
|
|
776
|
+
const lazy = this.keys.get(key)
|
|
777
|
+
|
|
778
|
+
if (!lazy) {
|
|
779
|
+
throw new LazyProofError(
|
|
780
|
+
`No verification key registered for ${system}:${circuitId}`,
|
|
781
|
+
'VK_NOT_FOUND'
|
|
782
|
+
)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return lazy.get()
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Preload verification keys for specified circuits
|
|
790
|
+
*/
|
|
791
|
+
preload(circuits: Array<{ system: ProofSystem; circuitId: string }>): void {
|
|
792
|
+
for (const { system, circuitId } of circuits) {
|
|
793
|
+
const key = this._makeKey(system, circuitId)
|
|
794
|
+
this.keys.get(key)?.preload()
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Preload all registered verification keys
|
|
800
|
+
*/
|
|
801
|
+
preloadAll(): void {
|
|
802
|
+
for (const lazy of this.keys.values()) {
|
|
803
|
+
lazy.preload()
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private _makeKey(system: ProofSystem, circuitId: string): string {
|
|
808
|
+
return `${system}:${circuitId}`
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// ─── Speculative Prefetching ──────────────────────────────────────────────────
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Configuration for speculative prefetching
|
|
816
|
+
*/
|
|
817
|
+
export interface PrefetchConfig {
|
|
818
|
+
/** Maximum proofs to prefetch */
|
|
819
|
+
readonly maxPrefetch: number
|
|
820
|
+
/** Prefetch when likelihood exceeds this threshold (0-1) */
|
|
821
|
+
readonly likelihoodThreshold: number
|
|
822
|
+
/** Time window for access pattern analysis (ms) */
|
|
823
|
+
readonly analysisWindowMs: number
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Default prefetch configuration
|
|
828
|
+
*/
|
|
829
|
+
export const DEFAULT_PREFETCH_CONFIG: PrefetchConfig = {
|
|
830
|
+
maxPrefetch: 5,
|
|
831
|
+
likelihoodThreshold: 0.7,
|
|
832
|
+
analysisWindowMs: 300000, // 5 minutes
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Speculative prefetcher for proofs
|
|
837
|
+
*/
|
|
838
|
+
export class SpeculativePrefetcher<T = SingleProof> {
|
|
839
|
+
private readonly config: PrefetchConfig
|
|
840
|
+
private readonly accessHistory: Array<{
|
|
841
|
+
circuitId: string
|
|
842
|
+
timestamp: number
|
|
843
|
+
}> = []
|
|
844
|
+
private readonly prefetched = new Map<string, LazyProof<T>>()
|
|
845
|
+
private readonly generators = new Map<string, ProofGenerator<T>>()
|
|
846
|
+
|
|
847
|
+
constructor(config: Partial<PrefetchConfig> = {}) {
|
|
848
|
+
this.config = { ...DEFAULT_PREFETCH_CONFIG, ...config }
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Register a proof generator for prefetching
|
|
853
|
+
*/
|
|
854
|
+
register(circuitId: string, generator: ProofGenerator<T>): void {
|
|
855
|
+
this.generators.set(circuitId, generator)
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Record an access and trigger prefetching
|
|
860
|
+
*/
|
|
861
|
+
recordAccess(circuitId: string): void {
|
|
862
|
+
// Record access
|
|
863
|
+
this.accessHistory.push({ circuitId, timestamp: Date.now() })
|
|
864
|
+
|
|
865
|
+
// Trim old history
|
|
866
|
+
const cutoff = Date.now() - this.config.analysisWindowMs
|
|
867
|
+
while (this.accessHistory.length > 0 && this.accessHistory[0].timestamp < cutoff) {
|
|
868
|
+
this.accessHistory.shift()
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Analyze and prefetch
|
|
872
|
+
this._prefetchLikely()
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Get a prefetched proof if available
|
|
877
|
+
*/
|
|
878
|
+
getPrefetched(circuitId: string): LazyProof<T> | null {
|
|
879
|
+
return this.prefetched.get(circuitId) ?? null
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Clear all prefetched proofs
|
|
884
|
+
*/
|
|
885
|
+
clear(): void {
|
|
886
|
+
for (const lazy of this.prefetched.values()) {
|
|
887
|
+
lazy.cancel()
|
|
888
|
+
}
|
|
889
|
+
this.prefetched.clear()
|
|
890
|
+
this.accessHistory.length = 0
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
private _prefetchLikely(): void {
|
|
894
|
+
// Calculate access frequencies
|
|
895
|
+
const frequencies = new Map<string, number>()
|
|
896
|
+
for (const { circuitId } of this.accessHistory) {
|
|
897
|
+
frequencies.set(circuitId, (frequencies.get(circuitId) ?? 0) + 1)
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Calculate likelihoods
|
|
901
|
+
const total = this.accessHistory.length
|
|
902
|
+
const likelihoods: Array<{ circuitId: string; likelihood: number }> = []
|
|
903
|
+
|
|
904
|
+
for (const [circuitId, count] of frequencies) {
|
|
905
|
+
const likelihood = count / total
|
|
906
|
+
if (likelihood >= this.config.likelihoodThreshold) {
|
|
907
|
+
likelihoods.push({ circuitId, likelihood })
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Sort by likelihood
|
|
912
|
+
likelihoods.sort((a, b) => b.likelihood - a.likelihood)
|
|
913
|
+
|
|
914
|
+
// Prefetch top candidates (respecting maxPrefetch limit including existing)
|
|
915
|
+
for (const { circuitId } of likelihoods) {
|
|
916
|
+
// Check total prefetched count (existing + new)
|
|
917
|
+
if (this.prefetched.size >= this.config.maxPrefetch) break
|
|
918
|
+
|
|
919
|
+
// Skip if already prefetched
|
|
920
|
+
if (this.prefetched.has(circuitId)) continue
|
|
921
|
+
|
|
922
|
+
// Skip if no generator
|
|
923
|
+
const generator = this.generators.get(circuitId)
|
|
924
|
+
if (!generator) continue
|
|
925
|
+
|
|
926
|
+
// Create lazy proof with immediate trigger
|
|
927
|
+
const lazy = new LazyProof(generator, {
|
|
928
|
+
...DEFAULT_LAZY_CONFIG,
|
|
929
|
+
trigger: 'immediate',
|
|
930
|
+
priority: 'low',
|
|
931
|
+
})
|
|
932
|
+
|
|
933
|
+
this.prefetched.set(circuitId, lazy)
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// ─── Error Class ──────────────────────────────────────────────────────────────
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Error codes for lazy proof operations
|
|
942
|
+
*/
|
|
943
|
+
export type LazyProofErrorCode =
|
|
944
|
+
| 'NOT_RESOLVED'
|
|
945
|
+
| 'CANCELLED'
|
|
946
|
+
| 'TIMEOUT'
|
|
947
|
+
| 'QUEUE_FULL'
|
|
948
|
+
| 'VK_NOT_FOUND'
|
|
949
|
+
| 'INTERNAL'
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Error class for lazy proof operations
|
|
953
|
+
*/
|
|
954
|
+
export class LazyProofError extends Error {
|
|
955
|
+
constructor(
|
|
956
|
+
message: string,
|
|
957
|
+
public readonly code: LazyProofErrorCode
|
|
958
|
+
) {
|
|
959
|
+
super(message)
|
|
960
|
+
this.name = 'LazyProofError'
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// ─── Factory Functions ────────────────────────────────────────────────────────
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Create a lazy proof with default configuration
|
|
968
|
+
*/
|
|
969
|
+
export function createLazyProof<T = SingleProof>(
|
|
970
|
+
generator: ProofGenerator<T>,
|
|
971
|
+
config?: Partial<LazyProofConfig>,
|
|
972
|
+
metadata?: { system?: ProofSystem; circuitId?: string }
|
|
973
|
+
): LazyProof<T> {
|
|
974
|
+
return new LazyProof<T>(
|
|
975
|
+
generator,
|
|
976
|
+
{ ...DEFAULT_LAZY_CONFIG, ...config },
|
|
977
|
+
metadata
|
|
978
|
+
)
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Create a proof generation queue
|
|
983
|
+
*/
|
|
984
|
+
export function createProofQueue<T = SingleProof>(
|
|
985
|
+
config?: Partial<ProofQueueConfig>
|
|
986
|
+
): ProofGenerationQueue<T> {
|
|
987
|
+
return new ProofGenerationQueue<T>(config)
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Create a verification key registry
|
|
992
|
+
*/
|
|
993
|
+
export function createVKRegistry(): VerificationKeyRegistry {
|
|
994
|
+
return new VerificationKeyRegistry()
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* Create a speculative prefetcher
|
|
999
|
+
*/
|
|
1000
|
+
export function createPrefetcher<T = SingleProof>(
|
|
1001
|
+
config?: Partial<PrefetchConfig>
|
|
1002
|
+
): SpeculativePrefetcher<T> {
|
|
1003
|
+
return new SpeculativePrefetcher<T>(config)
|
|
1004
|
+
}
|