@obolnetwork/obol-sdk 2.12.0 → 2.12.1
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/dist/browser/src/index.js +315 -136
- package/dist/browser/src/index.js.map +1 -1
- package/dist/cjs/src/blsUtils.js +19 -2
- package/dist/cjs/src/blsUtils.js.map +1 -1
- package/dist/cjs/src/index.js +321 -136
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/verification/clusterLockValidationWorker.js +14696 -0
- package/dist/cjs/src/verification/clusterLockValidationWorker.js.map +1 -0
- package/dist/cjs/src/verification/lockWorker.js +13 -1
- package/dist/cjs/src/verification/lockWorker.js.map +1 -1
- package/dist/cjs/src/verification/parallelPool.js +228 -35
- package/dist/cjs/src/verification/parallelPool.js.map +1 -1
- package/dist/esm/src/blsUtils.js +7 -3
- package/dist/esm/src/chunk-5ASVONSJ.js +10242 -0
- package/dist/esm/src/chunk-5ASVONSJ.js.map +1 -0
- package/dist/esm/src/{chunk-267HIPEB.js → chunk-LOSYOJC3.js} +16 -1
- package/dist/esm/src/{chunk-267HIPEB.js.map → chunk-LOSYOJC3.js.map} +1 -1
- package/dist/esm/src/chunk-RYTIXFRX.js +382 -0
- package/dist/esm/src/chunk-RYTIXFRX.js.map +1 -0
- package/dist/esm/src/index.js +213 -10340
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/verification/clusterLockValidationWorker.js +18 -0
- package/dist/esm/src/verification/clusterLockValidationWorker.js.map +1 -0
- package/dist/esm/src/verification/lockWorker.js +7 -2
- package/dist/esm/src/verification/lockWorker.js.map +1 -1
- package/dist/esm/src/verification/parallelPool.js +8 -2
- package/dist/types/src/blsUtils.d.ts +3 -0
- package/dist/types/src/errors.d.ts +13 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/services.d.ts +4 -1
- package/dist/types/src/types.d.ts +6 -0
- package/dist/types/src/verification/clusterLockValidationWorker.d.ts +1 -0
- package/dist/types/src/verification/common.d.ts +17 -7
- package/dist/types/src/verification/lockWorker.d.ts +7 -2
- package/dist/types/src/verification/parallelPool.d.ts +9 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/esm/src/chunk-OYZHSNKR.js +0 -186
- package/dist/esm/src/chunk-OYZHSNKR.js.map +0 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isValidClusterLock
|
|
3
|
+
} from "../chunk-5ASVONSJ.js";
|
|
4
|
+
import "../chunk-RYTIXFRX.js";
|
|
5
|
+
import "../chunk-LOSYOJC3.js";
|
|
6
|
+
|
|
7
|
+
// src/verification/clusterLockValidationWorker.ts
|
|
8
|
+
import { parentPort, workerData } from "worker_threads";
|
|
9
|
+
var input = workerData;
|
|
10
|
+
if (parentPort) {
|
|
11
|
+
const port = parentPort;
|
|
12
|
+
void isValidClusterLock(input.lock, input.safeRpcUrl).then((ok) => {
|
|
13
|
+
port.postMessage(ok);
|
|
14
|
+
}).catch(() => {
|
|
15
|
+
port.postMessage(false);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=clusterLockValidationWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/verification/clusterLockValidationWorker.ts"],"sourcesContent":["// Runs isValidClusterLock in a worker thread so obol-api's main thread stays responsive.\nimport { parentPort, workerData } from 'node:worker_threads';\nimport type { ClusterLock, SafeRpcUrl } from '../types.js';\nimport { isValidClusterLock } from './common.js';\n\nconst input = workerData as {\n lock: ClusterLock;\n safeRpcUrl?: SafeRpcUrl;\n};\n\nif (parentPort) {\n const port = parentPort;\n void isValidClusterLock(input.lock, input.safeRpcUrl)\n .then(ok => {\n port.postMessage(ok);\n })\n .catch(() => {\n port.postMessage(false);\n });\n}\n"],"mappings":";;;;;;;AACA,SAAS,YAAY,kBAAkB;AAIvC,IAAM,QAAQ;AAKd,IAAI,YAAY;AACd,QAAM,OAAO;AACb,OAAK,mBAAmB,MAAM,MAAM,MAAM,UAAU,EACjD,KAAK,QAAM;AACV,SAAK,YAAY,EAAE;AAAA,EACrB,CAAC,EACA,MAAM,MAAM;AACX,SAAK,YAAY,KAAK;AAAA,EACxB,CAAC;AACL;","names":[]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
blsAggregatePublicKeys,
|
|
3
|
+
blsAggregateSignatures,
|
|
2
4
|
blsRecoverDistributedPubkeyFromShares,
|
|
3
5
|
blsVerifyExtraShares,
|
|
4
6
|
blsVerifyMultiple
|
|
5
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-LOSYOJC3.js";
|
|
6
8
|
|
|
7
9
|
// src/verification/lockWorker.ts
|
|
8
10
|
import { parentPort, workerData } from "worker_threads";
|
|
@@ -32,12 +34,15 @@ function verifyBatchChunk(input) {
|
|
|
32
34
|
return blsVerifyMultiple(
|
|
33
35
|
input.pubkeys,
|
|
34
36
|
input.messages,
|
|
35
|
-
input.
|
|
37
|
+
blsAggregateSignatures(input.signatures)
|
|
36
38
|
);
|
|
37
39
|
}
|
|
38
40
|
function dispatch(input) {
|
|
39
41
|
if (input.mode === "shareBinding") return verifyShareBindingChunk(input);
|
|
40
42
|
if (input.mode === "verifyBatch") return verifyBatchChunk(input);
|
|
43
|
+
if (input.mode === "aggregatePubkeys") {
|
|
44
|
+
return blsAggregatePublicKeys(input.pubkeys);
|
|
45
|
+
}
|
|
41
46
|
return false;
|
|
42
47
|
}
|
|
43
48
|
if (parentPort) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/verification/lockWorker.ts"],"sourcesContent":["// Worker entry point loaded by parallelPool via Node's worker_threads.\n//\n// Two modes (dispatched on workerData.mode):\n// 'shareBinding' — Lagrange + extra-share verification for a validator chunk.\n// 'verifyBatch' — blsVerifyMultiple on a (pubkeys, messages, aggregateSig)\n// chunk of the deposit+builder batch.\n//\n//
|
|
1
|
+
{"version":3,"sources":["../../../../src/verification/lockWorker.ts"],"sourcesContent":["// Worker entry point loaded by parallelPool via Node's worker_threads.\n//\n// Two modes (dispatched on workerData.mode):\n// 'shareBinding' — Lagrange + extra-share verification for a validator chunk.\n// 'verifyBatch' — blsVerifyMultiple on a (pubkeys, messages, aggregateSig)\n// chunk of the deposit+builder batch.\n// 'aggregatePubkeys' — partial G1 aggregate of a pubkey chunk (for lock sig).\n//\n// shareBinding / verifyBatch return boolean; aggregatePubkeys returns bytes.\n\nimport { parentPort, workerData } from 'node:worker_threads';\nimport { fromHexString } from '@chainsafe/ssz';\nimport {\n blsAggregatePublicKeys,\n blsAggregateSignatures,\n blsRecoverDistributedPubkeyFromShares,\n blsVerifyExtraShares,\n blsVerifyMultiple,\n} from '../blsUtils.js';\n\nexport interface ShareBindingInput {\n mode: 'shareBinding';\n shares: string[][];\n distributedKeys: string[];\n threshold: number;\n}\n\nexport interface VerifyBatchInput {\n mode: 'verifyBatch';\n pubkeys: Uint8Array[];\n messages: Uint8Array[];\n signatures: Uint8Array[];\n}\n\nexport interface AggregatePubkeysInput {\n mode: 'aggregatePubkeys';\n pubkeys: Uint8Array[];\n}\n\nexport type WorkerInput =\n | ShareBindingInput\n | VerifyBatchInput\n | AggregatePubkeysInput;\n\nexport type WorkerResult = boolean | Uint8Array;\n\nfunction verifyShareBindingChunk(input: ShareBindingInput): boolean {\n const { shares, distributedKeys, threshold } = input;\n if (shares.length !== distributedKeys.length) return false;\n\n for (let i = 0; i < shares.length; i++) {\n const sharesBytes = shares[i].map(s => fromHexString(s));\n const dkBytes = fromHexString(distributedKeys[i]);\n\n const recovered = blsRecoverDistributedPubkeyFromShares(\n sharesBytes,\n threshold,\n );\n if (!recovered) return false;\n if (recovered.length !== dkBytes.length) return false;\n for (let j = 0; j < recovered.length; j++) {\n if (recovered[j] !== dkBytes[j]) return false;\n }\n if (!blsVerifyExtraShares(sharesBytes, threshold, dkBytes)) {\n return false;\n }\n }\n return true;\n}\n\nfunction verifyBatchChunk(input: VerifyBatchInput): boolean {\n return blsVerifyMultiple(\n input.pubkeys,\n input.messages,\n blsAggregateSignatures(input.signatures),\n );\n}\n\nfunction dispatch(input: WorkerInput): WorkerResult {\n if (input.mode === 'shareBinding') return verifyShareBindingChunk(input);\n if (input.mode === 'verifyBatch') return verifyBatchChunk(input);\n if (input.mode === 'aggregatePubkeys') {\n return blsAggregatePublicKeys(input.pubkeys);\n }\n return false;\n}\n\nif (parentPort) {\n try {\n parentPort.postMessage(dispatch(workerData as WorkerInput));\n } catch {\n parentPort.postMessage(false);\n }\n}\n"],"mappings":";;;;;;;;;AAUA,SAAS,YAAY,kBAAkB;AACvC,SAAS,qBAAqB;AAmC9B,SAAS,wBAAwB,OAAmC;AAClE,QAAM,EAAE,QAAQ,iBAAiB,UAAU,IAAI;AAC/C,MAAI,OAAO,WAAW,gBAAgB,OAAQ,QAAO;AAErD,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,cAAc,OAAO,CAAC,EAAE,IAAI,OAAK,cAAc,CAAC,CAAC;AACvD,UAAM,UAAU,cAAc,gBAAgB,CAAC,CAAC;AAEhD,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,UAAU,WAAW,QAAQ,OAAQ,QAAO;AAChD,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,EAAG,QAAO;AAAA,IAC1C;AACA,QAAI,CAAC,qBAAqB,aAAa,WAAW,OAAO,GAAG;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAkC;AAC1D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,uBAAuB,MAAM,UAAU;AAAA,EACzC;AACF;AAEA,SAAS,SAAS,OAAkC;AAClD,MAAI,MAAM,SAAS,eAAgB,QAAO,wBAAwB,KAAK;AACvE,MAAI,MAAM,SAAS,cAAe,QAAO,iBAAiB,KAAK;AAC/D,MAAI,MAAM,SAAS,oBAAoB;AACrC,WAAO,uBAAuB,MAAM,OAAO;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,IAAI,YAAY;AACd,MAAI;AACF,eAAW,YAAY,SAAS,UAAyB,CAAC;AAAA,EAC5D,SAAQ;AACN,eAAW,YAAY,KAAK;AAAA,EAC9B;AACF;","names":[]}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
validateClusterLockInWorker,
|
|
3
|
+
verifyAggregateParallel,
|
|
2
4
|
verifyBatchParallel,
|
|
5
|
+
verifyBlsChecksParallel,
|
|
3
6
|
verifySharesBinding
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-RYTIXFRX.js";
|
|
8
|
+
import "../chunk-LOSYOJC3.js";
|
|
6
9
|
export {
|
|
10
|
+
validateClusterLockInWorker,
|
|
11
|
+
verifyAggregateParallel,
|
|
7
12
|
verifyBatchParallel,
|
|
13
|
+
verifyBlsChecksParallel,
|
|
8
14
|
verifySharesBinding
|
|
9
15
|
};
|
|
10
16
|
//# sourceMappingURL=parallelPool.js.map
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export declare function blsVerify(pubkey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
|
|
2
|
+
export declare function blsAggregatePublicKeys(pubkeys: Uint8Array[]): Uint8Array;
|
|
2
3
|
export declare function blsVerifyAggregate(pubkeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean;
|
|
4
|
+
/** Verify when the pubkey set is already aggregated to a single G1 key. */
|
|
5
|
+
export declare function blsVerifyWithAggregatedPubkey(aggregatedPubkey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
|
|
3
6
|
export declare function blsVerifyMultiple(pubkeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean;
|
|
4
7
|
export declare function blsAggregateSignatures(signatures: Uint8Array[]): Uint8Array;
|
|
5
8
|
export declare function blsRecoverDistributedPubkeyFromShares(pubshares: Uint8Array[], threshold: number): Uint8Array | null;
|
|
@@ -25,3 +25,16 @@ export declare class UnsupportedChainError extends Error {
|
|
|
25
25
|
name: string;
|
|
26
26
|
constructor(chainId: number, operation: string);
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Thrown when full lock validation (`validateClusterLock` worker path) exceeds
|
|
30
|
+
* the worker time limit (large clusters). HTTP gateways should respond with
|
|
31
|
+
* **504**; this is distinct from cryptographic failure (**false** → **400**).
|
|
32
|
+
*/
|
|
33
|
+
export declare class ClusterLockValidationTimeoutError extends Error {
|
|
34
|
+
readonly timeoutMs: number;
|
|
35
|
+
name: string;
|
|
36
|
+
/**
|
|
37
|
+
* @param timeoutMs - Same value as SDK whole-lock validation worker timeout.
|
|
38
|
+
*/
|
|
39
|
+
constructor(timeoutMs: number);
|
|
40
|
+
}
|
|
@@ -9,7 +9,7 @@ export * from './services.js';
|
|
|
9
9
|
export * from './verification/signature-validator.js';
|
|
10
10
|
export * from './verification/common.js';
|
|
11
11
|
export * from './constants.js';
|
|
12
|
-
export { ConflictError, SignerRequiredError, UnsupportedChainError, } from './errors.js';
|
|
12
|
+
export { ConflictError, ClusterLockValidationTimeoutError, SignerRequiredError, UnsupportedChainError, } from './errors.js';
|
|
13
13
|
export { Incentives } from './incentives/incentives.js';
|
|
14
14
|
export { Exit } from './exits/exit.js';
|
|
15
15
|
export { ObolSplits } from './splits/splits.js';
|
|
@@ -16,7 +16,10 @@ import { type SafeRpcUrl, type ClusterLock } from './types.js';
|
|
|
16
16
|
* @param safeRpcUrl - Optional RPC URL for Safe Wallet signature verification.
|
|
17
17
|
* If omitted, falls back to the `RPC_MAINNET` / `RPC_HOODI` / etc. env vars.
|
|
18
18
|
* @returns `true` if the lock is cryptographically valid; `false` if invalid
|
|
19
|
-
* (e.g. missing keys, invalid signatures, hash mismatches)
|
|
19
|
+
* (e.g. missing keys, invalid signatures, hash mismatches).
|
|
20
|
+
* @throws `ClusterLockValidationTimeoutError` when whole-lock validation
|
|
21
|
+
* exceeds the SDK worker deadline (typically large clusters). HTTP APIs should map
|
|
22
|
+
* this to **504 Gateway Timeout**.
|
|
20
23
|
*
|
|
21
24
|
* @example
|
|
22
25
|
* ```typescript
|
|
@@ -241,6 +241,12 @@ export type BuilderRegistration = {
|
|
|
241
241
|
/** BLS signature of the builder registration message. */
|
|
242
242
|
signature: string;
|
|
243
243
|
};
|
|
244
|
+
/** Pubkey + message + signature checked together in batch BLS verification. */
|
|
245
|
+
export type BlsSignatureCheck = {
|
|
246
|
+
pubkey: Uint8Array;
|
|
247
|
+
message: Uint8Array;
|
|
248
|
+
signature: Uint8Array;
|
|
249
|
+
};
|
|
244
250
|
/**
|
|
245
251
|
* Required deposit data for validator activation
|
|
246
252
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ClusterDefinition, type ClusterLock, type DepositData, type DistributedValidator, type SafeRpcUrl } from '../types.js';
|
|
1
|
+
import { type BlsSignatureCheck, type ClusterDefinition, type ClusterLock, type DepositData, type DistributedValidator, type SafeRpcUrl } from '../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* @param cluster The cluster configuration or the cluster definition
|
|
4
4
|
* @param configOnly a boolean to indicate config hash or definition hash
|
|
@@ -11,21 +11,31 @@ export declare const clusterConfigOrDefinitionHash: (cluster: ClusterDefinition,
|
|
|
11
11
|
* @returns The cluster lock hash in of the corresponding cluster lock
|
|
12
12
|
*/
|
|
13
13
|
export declare const clusterLockHash: (clusterLock: ClusterLock) => string;
|
|
14
|
+
export declare const depositDomainForFork: (forkVersion: string) => Uint8Array;
|
|
15
|
+
export declare const builderDomainForFork: (forkVersion: string) => Uint8Array;
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
* Structural deposit checks + signing root (no BLS). Used before batch BLS verify.
|
|
18
|
+
*/
|
|
19
|
+
export declare const validateDepositDataStructure: (distributedPublicKey: string, depositData: Partial<DepositData>, withdrawalAddress: string, forkVersion: string, compounding?: boolean, precomputedDepositDomain?: Uint8Array) => {
|
|
20
|
+
valid: boolean;
|
|
21
|
+
message: Uint8Array;
|
|
22
|
+
};
|
|
23
|
+
/** Deposit fields + BLS triple for batch verification. Returns null if structure is invalid. */
|
|
24
|
+
export declare const depositBlsCheck: (distributedPublicKey: string, depositData: Partial<DepositData>, withdrawalAddress: string, forkVersion: string, compounding?: boolean, precomputedDepositDomain?: Uint8Array) => BlsSignatureCheck | null;
|
|
25
|
+
/**
|
|
26
|
+
* Verify deposit data withdrawal credintials and signature (structure + BLS in one call).
|
|
27
|
+
* Prefer `depositBlsCheck` + batch verify in lock validation for large locks.
|
|
20
28
|
*/
|
|
21
29
|
export declare const verifyDepositData: (distributedPublicKey: string, depositData: Partial<DepositData>, withdrawalAddress: string, forkVersion: string, compounding?: boolean) => {
|
|
22
30
|
isValidDepositData: boolean;
|
|
23
31
|
depositDataMsg: Uint8Array;
|
|
24
32
|
};
|
|
25
|
-
export declare const verifyBuilderRegistration: (validator: DistributedValidator, feeRecipientAddress: string, forkVersion: string) => {
|
|
33
|
+
export declare const verifyBuilderRegistration: (validator: DistributedValidator, feeRecipientAddress: string, forkVersion: string, precomputedBuilderDomain?: Uint8Array) => {
|
|
26
34
|
isValidBuilderRegistration: boolean;
|
|
27
35
|
builderRegistrationMsg: Uint8Array;
|
|
28
36
|
};
|
|
37
|
+
/** Builder registration BLS triple for batch verification. Returns null if structure is invalid. */
|
|
38
|
+
export declare const builderBlsCheck: (validator: DistributedValidator, feeRecipientAddress: string, forkVersion: string, precomputedBuilderDomain?: Uint8Array) => BlsSignatureCheck | null;
|
|
29
39
|
export declare const verifyNodeSignatures: (clusterLock: ClusterLock) => boolean;
|
|
30
40
|
export declare const signingRoot: (domain: Uint8Array, messageBuffer: Buffer) => Uint8Array;
|
|
31
41
|
/**
|
|
@@ -8,6 +8,11 @@ export interface VerifyBatchInput {
|
|
|
8
8
|
mode: 'verifyBatch';
|
|
9
9
|
pubkeys: Uint8Array[];
|
|
10
10
|
messages: Uint8Array[];
|
|
11
|
-
|
|
11
|
+
signatures: Uint8Array[];
|
|
12
12
|
}
|
|
13
|
-
export
|
|
13
|
+
export interface AggregatePubkeysInput {
|
|
14
|
+
mode: 'aggregatePubkeys';
|
|
15
|
+
pubkeys: Uint8Array[];
|
|
16
|
+
}
|
|
17
|
+
export type WorkerInput = ShareBindingInput | VerifyBatchInput | AggregatePubkeysInput;
|
|
18
|
+
export type WorkerResult = boolean | Uint8Array;
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
+
import type { BlsSignatureCheck, ClusterLock, SafeRpcUrl } from '../types.js';
|
|
1
2
|
export declare function verifySharesBinding(shares: string[][], distributedKeys: string[], threshold: number): Promise<boolean>;
|
|
3
|
+
/** Verify deposit + builder BLS signatures collected from `depositBlsCheck` / `builderBlsCheck`. */
|
|
4
|
+
export declare function verifyBlsChecksParallel(checks: BlsSignatureCheck[]): Promise<boolean>;
|
|
2
5
|
export declare function verifyBatchParallel(pubkeys: Uint8Array[], messages: Uint8Array[], signatures: Uint8Array[]): Promise<boolean>;
|
|
6
|
+
export declare function verifyAggregateParallel(pubkeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Large locks: run full validation off the main thread (obol-api stays responsive).
|
|
9
|
+
* Returns null when workers are unavailable — caller should use sync validation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateClusterLockInWorker(lock: ClusterLock, safeRpcUrl?: SafeRpcUrl): Promise<boolean | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../../tsup.config.ts","../../src/ajv.ts","../../src/base.ts","../../src/blsUtils.ts","../../src/bytecodes.ts","../../src/constants.ts","../../src/errors.ts","../../src/index.ts","../../src/schema.ts","../../src/services.ts","../../src/types.ts","../../src/utils.ts","../../src/abi/BatchDeposit.ts","../../src/abi/MerkleDistributorWithDeadline.ts","../../src/abi/Multicall3.ts","../../src/abi/OVM.ts","../../src/abi/OWR.ts","../../src/abi/SplitMain.ts","../../src/abi/splitV2FactoryAbi.ts","../../src/eoa/eoa.ts","../../src/eoa/eoaHelpers.ts","../../src/exits/ethUtils.ts","../../src/exits/exit.ts","../../src/exits/verificationHelpers.ts","../../src/incentives/incentiveHelpers.ts","../../src/incentives/incentives.ts","../../src/splits/splitHelpers.ts","../../src/splits/splits.ts","../../src/verification/common.ts","../../src/verification/lockWorker.ts","../../src/verification/parallelPool.ts","../../src/verification/signature-validator.ts","../../src/verification/sszTypes.ts","../../src/verification/v1.10.0.ts","../../src/verification/v1.6.0.ts","../../src/verification/v1.7.0.ts","../../src/verification/v1.8.0.ts","../../test/fixtures.ts","../../test/client/ajv.spec.ts","../../test/client/methods.spec.ts","../../test/eoa/eoa.spec.ts","../../test/exit/ethUtils.spec.ts","../../test/exit/exit.spec.ts","../../test/exit/verificationHelpers.spec.ts","../../test/incentives/incentives.spec.ts","../../test/splits/splits.spec.ts","../../test/verification/parallelPool.spec.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../../tsup.config.ts","../../src/ajv.ts","../../src/base.ts","../../src/blsUtils.ts","../../src/bytecodes.ts","../../src/constants.ts","../../src/errors.ts","../../src/index.ts","../../src/schema.ts","../../src/services.ts","../../src/types.ts","../../src/utils.ts","../../src/abi/BatchDeposit.ts","../../src/abi/MerkleDistributorWithDeadline.ts","../../src/abi/Multicall3.ts","../../src/abi/OVM.ts","../../src/abi/OWR.ts","../../src/abi/SplitMain.ts","../../src/abi/splitV2FactoryAbi.ts","../../src/eoa/eoa.ts","../../src/eoa/eoaHelpers.ts","../../src/exits/ethUtils.ts","../../src/exits/exit.ts","../../src/exits/verificationHelpers.ts","../../src/incentives/incentiveHelpers.ts","../../src/incentives/incentives.ts","../../src/splits/splitHelpers.ts","../../src/splits/splits.ts","../../src/verification/clusterLockValidationWorker.ts","../../src/verification/common.ts","../../src/verification/lockWorker.ts","../../src/verification/parallelPool.ts","../../src/verification/signature-validator.ts","../../src/verification/sszTypes.ts","../../src/verification/v1.10.0.ts","../../src/verification/v1.6.0.ts","../../src/verification/v1.7.0.ts","../../src/verification/v1.8.0.ts","../../test/fixtures.ts","../../test/client/ajv.spec.ts","../../test/client/methods.spec.ts","../../test/eoa/eoa.spec.ts","../../test/exit/ethUtils.spec.ts","../../test/exit/exit.spec.ts","../../test/exit/verificationHelpers.spec.ts","../../test/incentives/incentives.spec.ts","../../test/splits/splits.spec.ts","../../test/verification/parallelPool.spec.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__async,
|
|
3
|
-
__require,
|
|
4
|
-
blsAggregateSignatures,
|
|
5
|
-
blsRecoverDistributedPubkeyFromShares,
|
|
6
|
-
blsVerifyExtraShares,
|
|
7
|
-
blsVerifyMultiple
|
|
8
|
-
} from "./chunk-267HIPEB.js";
|
|
9
|
-
|
|
10
|
-
// src/verification/parallelPool.ts
|
|
11
|
-
import { fromHexString } from "@chainsafe/ssz";
|
|
12
|
-
var MIN_PARALLEL_VALIDATORS = 50;
|
|
13
|
-
var MIN_PARALLEL_BATCH_PAIRS = 100;
|
|
14
|
-
var MAX_WORKERS = 8;
|
|
15
|
-
var MIN_VALIDATORS_PER_WORKER = 25;
|
|
16
|
-
var MIN_PAIRS_PER_WORKER = 50;
|
|
17
|
-
var WORKER_TIMEOUT_MS = 6e4;
|
|
18
|
-
var workerThreadsCache;
|
|
19
|
-
var osCache;
|
|
20
|
-
var workerPathCache;
|
|
21
|
-
function loadWorkerThreads() {
|
|
22
|
-
if (workerThreadsCache !== void 0) return workerThreadsCache;
|
|
23
|
-
try {
|
|
24
|
-
workerThreadsCache = __require("worker_threads");
|
|
25
|
-
} catch (e) {
|
|
26
|
-
workerThreadsCache = null;
|
|
27
|
-
}
|
|
28
|
-
return workerThreadsCache;
|
|
29
|
-
}
|
|
30
|
-
function loadOs() {
|
|
31
|
-
if (osCache !== void 0) return osCache;
|
|
32
|
-
try {
|
|
33
|
-
osCache = __require("os");
|
|
34
|
-
} catch (e) {
|
|
35
|
-
osCache = null;
|
|
36
|
-
}
|
|
37
|
-
return osCache;
|
|
38
|
-
}
|
|
39
|
-
function getWorkerPath() {
|
|
40
|
-
if (workerPathCache !== void 0) return workerPathCache;
|
|
41
|
-
if (typeof __dirname === "undefined") return workerPathCache = null;
|
|
42
|
-
const path = __require("path");
|
|
43
|
-
const candidate = path.join(__dirname, "lockWorker.js");
|
|
44
|
-
try {
|
|
45
|
-
const fs = __require("fs");
|
|
46
|
-
if (!fs.existsSync(candidate)) return workerPathCache = null;
|
|
47
|
-
} catch (e) {
|
|
48
|
-
return workerPathCache = null;
|
|
49
|
-
}
|
|
50
|
-
return workerPathCache = candidate;
|
|
51
|
-
}
|
|
52
|
-
function chunkArrays(arr, n) {
|
|
53
|
-
const size = Math.ceil(arr.length / n);
|
|
54
|
-
const out = [];
|
|
55
|
-
for (let i = 0; i < arr.length; i += size) {
|
|
56
|
-
out.push(arr.slice(i, i + size));
|
|
57
|
-
}
|
|
58
|
-
return out;
|
|
59
|
-
}
|
|
60
|
-
function verifySharesSync(shares, distributedKeys, threshold) {
|
|
61
|
-
for (let i = 0; i < shares.length; i++) {
|
|
62
|
-
const sharesBytes = shares[i].map((s) => fromHexString(s));
|
|
63
|
-
const dkBytes = fromHexString(distributedKeys[i]);
|
|
64
|
-
const recovered = blsRecoverDistributedPubkeyFromShares(
|
|
65
|
-
sharesBytes,
|
|
66
|
-
threshold
|
|
67
|
-
);
|
|
68
|
-
if (!recovered) return false;
|
|
69
|
-
if (recovered.length !== dkBytes.length) return false;
|
|
70
|
-
for (let j = 0; j < recovered.length; j++) {
|
|
71
|
-
if (recovered[j] !== dkBytes[j]) return false;
|
|
72
|
-
}
|
|
73
|
-
if (!blsVerifyExtraShares(sharesBytes, threshold, dkBytes)) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
function runWorker(wt, workerFile, data) {
|
|
80
|
-
return __async(this, null, function* () {
|
|
81
|
-
return yield new Promise((resolve) => {
|
|
82
|
-
let settled = false;
|
|
83
|
-
const worker = new wt.Worker(workerFile, { workerData: data });
|
|
84
|
-
const finish = (result) => {
|
|
85
|
-
if (settled) return;
|
|
86
|
-
settled = true;
|
|
87
|
-
clearTimeout(timer);
|
|
88
|
-
worker.terminate();
|
|
89
|
-
resolve(result);
|
|
90
|
-
};
|
|
91
|
-
const timer = setTimeout(() => {
|
|
92
|
-
finish(false);
|
|
93
|
-
}, WORKER_TIMEOUT_MS);
|
|
94
|
-
worker.once("message", (msg) => {
|
|
95
|
-
finish(msg === true);
|
|
96
|
-
});
|
|
97
|
-
worker.once("error", () => {
|
|
98
|
-
finish(false);
|
|
99
|
-
});
|
|
100
|
-
worker.once("exit", (code) => {
|
|
101
|
-
if (code !== 0) finish(false);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
function poolSize(itemCount, minPerWorker) {
|
|
107
|
-
const wt = loadWorkerThreads();
|
|
108
|
-
const os = loadOs();
|
|
109
|
-
const workerFile = getWorkerPath();
|
|
110
|
-
const numCpus = os ? os.cpus().length : 1;
|
|
111
|
-
const numWorkers = Math.min(
|
|
112
|
-
MAX_WORKERS,
|
|
113
|
-
Math.max(1, Math.floor(itemCount / minPerWorker)),
|
|
114
|
-
numCpus
|
|
115
|
-
);
|
|
116
|
-
return { numWorkers, wt, workerFile };
|
|
117
|
-
}
|
|
118
|
-
function verifySharesBinding(shares, distributedKeys, threshold) {
|
|
119
|
-
return __async(this, null, function* () {
|
|
120
|
-
if (shares.length !== distributedKeys.length) return false;
|
|
121
|
-
if (shares.length === 0) return true;
|
|
122
|
-
const { numWorkers, wt, workerFile } = poolSize(
|
|
123
|
-
shares.length,
|
|
124
|
-
MIN_VALIDATORS_PER_WORKER
|
|
125
|
-
);
|
|
126
|
-
if (wt === null || workerFile === null || shares.length < MIN_PARALLEL_VALIDATORS || numWorkers < 2) {
|
|
127
|
-
return verifySharesSync(shares, distributedKeys, threshold);
|
|
128
|
-
}
|
|
129
|
-
const shareChunks = chunkArrays(shares, numWorkers);
|
|
130
|
-
const keyChunks = chunkArrays(distributedKeys, numWorkers);
|
|
131
|
-
const results = yield Promise.all(
|
|
132
|
-
shareChunks.map(
|
|
133
|
-
(chunk, i) => __async(null, null, function* () {
|
|
134
|
-
return yield runWorker(wt, workerFile, {
|
|
135
|
-
mode: "shareBinding",
|
|
136
|
-
shares: chunk,
|
|
137
|
-
distributedKeys: keyChunks[i],
|
|
138
|
-
threshold
|
|
139
|
-
});
|
|
140
|
-
})
|
|
141
|
-
)
|
|
142
|
-
);
|
|
143
|
-
return results.every(Boolean);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
function verifyBatchParallel(pubkeys, messages, signatures) {
|
|
147
|
-
return __async(this, null, function* () {
|
|
148
|
-
if (pubkeys.length !== messages.length || pubkeys.length !== signatures.length) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
if (pubkeys.length === 0) return true;
|
|
152
|
-
const { numWorkers, wt, workerFile } = poolSize(
|
|
153
|
-
pubkeys.length,
|
|
154
|
-
MIN_PAIRS_PER_WORKER
|
|
155
|
-
);
|
|
156
|
-
if (wt === null || workerFile === null || pubkeys.length < MIN_PARALLEL_BATCH_PAIRS || numWorkers < 2) {
|
|
157
|
-
return blsVerifyMultiple(
|
|
158
|
-
pubkeys,
|
|
159
|
-
messages,
|
|
160
|
-
blsAggregateSignatures(signatures)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
const pkChunks = chunkArrays(pubkeys, numWorkers);
|
|
164
|
-
const msgChunks = chunkArrays(messages, numWorkers);
|
|
165
|
-
const sigChunks = chunkArrays(signatures, numWorkers);
|
|
166
|
-
const results = yield Promise.all(
|
|
167
|
-
pkChunks.map(
|
|
168
|
-
(pks, i) => __async(null, null, function* () {
|
|
169
|
-
return yield runWorker(wt, workerFile, {
|
|
170
|
-
mode: "verifyBatch",
|
|
171
|
-
pubkeys: pks,
|
|
172
|
-
messages: msgChunks[i],
|
|
173
|
-
aggregateSignature: blsAggregateSignatures(sigChunks[i])
|
|
174
|
-
});
|
|
175
|
-
})
|
|
176
|
-
)
|
|
177
|
-
);
|
|
178
|
-
return results.every(Boolean);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export {
|
|
183
|
-
verifySharesBinding,
|
|
184
|
-
verifyBatchParallel
|
|
185
|
-
};
|
|
186
|
-
//# sourceMappingURL=chunk-OYZHSNKR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/verification/parallelPool.ts"],"sourcesContent":["// Parallel BLS verification via Node worker_threads.\n//\n// IMPORTANT: only the CJS build actually runs in parallel. ESM Node and\n// browser bundles transparently fall back to sync. See the matrix in\n// PARALLEL_VALIDATION_PLAN.md. The main consumer flow (charon DKG ->\n// obol-api NestJS handler -> SDK CJS) is CJS, so it gets the speedup.\n//\n// Strategy:\n// - Look up the worker file via __dirname (CJS only). If undefined or the\n// file isn't where we expect (ESM, browser, source-mode tsx/jest), return\n// undefined and fall back to sync.\n// - Below MIN_PARALLEL_* thresholds, sync wins (worker spin-up dominates).\n// - Spawn one worker per chunk, await all, collapse to a single boolean.\n\nimport { fromHexString } from '@chainsafe/ssz';\nimport {\n blsAggregateSignatures,\n blsRecoverDistributedPubkeyFromShares,\n blsVerifyExtraShares,\n blsVerifyMultiple,\n} from '../blsUtils.js';\n// Type-only imports — erased at compile time, so they don't pull node:*\n// modules into the browser bundle.\nimport type * as WTNs from 'node:worker_threads';\nimport type * as OsNs from 'node:os';\nimport type * as PathNs from 'node:path';\nimport type * as FsNs from 'node:fs';\nimport type { WorkerInput } from './lockWorker.js';\n\nconst MIN_PARALLEL_VALIDATORS = 50;\nconst MIN_PARALLEL_BATCH_PAIRS = 100;\nconst MAX_WORKERS = 8;\nconst MIN_VALIDATORS_PER_WORKER = 25;\nconst MIN_PAIRS_PER_WORKER = 50;\n// Hard ceiling so a stuck worker can't leak past obol-api's HTTP timeout.\n// Biggest legitimate batch (~1000 pairs) finishes in ~3s on the bench; 60s\n// is conservative enough to never false-trip on real input.\nconst WORKER_TIMEOUT_MS = 60_000;\n\ntype WorkerThreads = typeof WTNs;\ntype NodeOs = typeof OsNs;\n\nlet workerThreadsCache: WorkerThreads | null | undefined;\nlet osCache: NodeOs | null | undefined;\n// Tri-state: undefined = uncached, null = checked & unavailable, string = path.\nlet workerPathCache: string | null | undefined;\n\nfunction loadWorkerThreads(): WorkerThreads | null {\n if (workerThreadsCache !== undefined) return workerThreadsCache;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n workerThreadsCache = require('node:worker_threads') as WorkerThreads;\n } catch {\n workerThreadsCache = null;\n }\n return workerThreadsCache;\n}\n\nfunction loadOs(): NodeOs | null {\n if (osCache !== undefined) return osCache;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n osCache = require('node:os') as NodeOs;\n } catch {\n osCache = null;\n }\n return osCache;\n}\n\nfunction getWorkerPath(): string | null {\n if (workerPathCache !== undefined) return workerPathCache;\n // CJS only. In ESM and browser builds __dirname is undefined, so this\n // memoizes null and the caller falls back to sync. See plan for the\n // full coverage matrix.\n if (typeof __dirname === 'undefined') return (workerPathCache = null);\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const path = require('node:path') as typeof PathNs;\n const candidate = path.join(__dirname, 'lockWorker.js');\n // Sanity check: running from source (tsx, ts-node, jest without a build)\n // also hits the CJS branch but the .js file isn't there yet. Without\n // memoizing null we'd re-run existsSync on every call.\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const fs = require('node:fs') as typeof FsNs;\n if (!fs.existsSync(candidate)) return (workerPathCache = null);\n } catch {\n return (workerPathCache = null);\n }\n return (workerPathCache = candidate);\n}\n\nfunction chunkArrays<T>(arr: T[], n: number): T[][] {\n const size = Math.ceil(arr.length / n);\n const out: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n out.push(arr.slice(i, i + size));\n }\n return out;\n}\n\nfunction verifySharesSync(\n shares: string[][],\n distributedKeys: string[],\n threshold: number,\n): boolean {\n for (let i = 0; i < shares.length; i++) {\n const sharesBytes = shares[i].map(s => fromHexString(s));\n const dkBytes = fromHexString(distributedKeys[i]);\n const recovered = blsRecoverDistributedPubkeyFromShares(\n sharesBytes,\n threshold,\n );\n if (!recovered) return false;\n if (recovered.length !== dkBytes.length) return false;\n for (let j = 0; j < recovered.length; j++) {\n if (recovered[j] !== dkBytes[j]) return false;\n }\n if (!blsVerifyExtraShares(sharesBytes, threshold, dkBytes)) {\n return false;\n }\n }\n return true;\n}\n\nasync function runWorker(\n wt: WorkerThreads,\n workerFile: string,\n data: WorkerInput,\n): Promise<boolean> {\n return await new Promise(resolve => {\n let settled = false;\n const worker = new wt.Worker(workerFile, { workerData: data });\n const finish = (result: boolean): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n resolve(result);\n };\n const timer = setTimeout(() => {\n finish(false);\n }, WORKER_TIMEOUT_MS);\n worker.once('message', (msg: unknown) => {\n finish(msg === true);\n });\n worker.once('error', () => {\n finish(false);\n });\n worker.once('exit', code => {\n if (code !== 0) finish(false);\n });\n });\n}\n\nfunction poolSize(\n itemCount: number,\n minPerWorker: number,\n): {\n numWorkers: number;\n wt: WorkerThreads | null;\n workerFile: string | null;\n} {\n const wt = loadWorkerThreads();\n const os = loadOs();\n const workerFile = getWorkerPath();\n const numCpus = os ? os.cpus().length : 1;\n const numWorkers = Math.min(\n MAX_WORKERS,\n Math.max(1, Math.floor(itemCount / minPerWorker)),\n numCpus,\n );\n return { numWorkers, wt, workerFile };\n}\n\nexport async function verifySharesBinding(\n shares: string[][],\n distributedKeys: string[],\n threshold: number,\n): Promise<boolean> {\n if (shares.length !== distributedKeys.length) return false;\n if (shares.length === 0) return true;\n\n const { numWorkers, wt, workerFile } = poolSize(\n shares.length,\n MIN_VALIDATORS_PER_WORKER,\n );\n\n // Inline the guard so TS narrows wt/workerFile for the parallel path below\n // (avoids non-null assertions).\n if (\n wt === null ||\n workerFile === null ||\n shares.length < MIN_PARALLEL_VALIDATORS ||\n numWorkers < 2\n ) {\n return verifySharesSync(shares, distributedKeys, threshold);\n }\n\n const shareChunks = chunkArrays(shares, numWorkers);\n const keyChunks = chunkArrays(distributedKeys, numWorkers);\n\n const results = await Promise.all(\n shareChunks.map(\n async (chunk, i) =>\n await runWorker(wt, workerFile, {\n mode: 'shareBinding',\n shares: chunk,\n distributedKeys: keyChunks[i],\n threshold,\n }),\n ),\n );\n return results.every(Boolean);\n}\n\n// Verify a batch of (pubkey, message, individual signature) triples.\n// Sync path aggregates all sigs and runs blsVerifyMultiple once (matches the\n// previous behavior). Parallel path splits into chunks; each chunk's sigs are\n// aggregated and verified independently — same total pairing count, K× wall\n// time speedup.\nexport async function verifyBatchParallel(\n pubkeys: Uint8Array[],\n messages: Uint8Array[],\n signatures: Uint8Array[],\n): Promise<boolean> {\n if (\n pubkeys.length !== messages.length ||\n pubkeys.length !== signatures.length\n ) {\n return false;\n }\n if (pubkeys.length === 0) return true;\n\n const { numWorkers, wt, workerFile } = poolSize(\n pubkeys.length,\n MIN_PAIRS_PER_WORKER,\n );\n\n if (\n wt === null ||\n workerFile === null ||\n pubkeys.length < MIN_PARALLEL_BATCH_PAIRS ||\n numWorkers < 2\n ) {\n return blsVerifyMultiple(\n pubkeys,\n messages,\n blsAggregateSignatures(signatures),\n );\n }\n\n const pkChunks = chunkArrays(pubkeys, numWorkers);\n const msgChunks = chunkArrays(messages, numWorkers);\n const sigChunks = chunkArrays(signatures, numWorkers);\n\n const results = await Promise.all(\n pkChunks.map(\n async (pks, i) =>\n await runWorker(wt, workerFile, {\n mode: 'verifyBatch',\n pubkeys: pks,\n messages: msgChunks[i],\n aggregateSignature: blsAggregateSignatures(sigChunks[i]),\n }),\n ),\n );\n return results.every(Boolean);\n}\n"],"mappings":"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","names":[]}
|