@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
|
@@ -58,7 +58,10 @@ var __async = (__this, __arguments, generator) => {
|
|
|
58
58
|
// src/verification/parallelPool.ts
|
|
59
59
|
var parallelPool_exports = {};
|
|
60
60
|
__export(parallelPool_exports, {
|
|
61
|
+
validateClusterLockInWorker: () => validateClusterLockInWorker,
|
|
62
|
+
verifyAggregateParallel: () => verifyAggregateParallel,
|
|
61
63
|
verifyBatchParallel: () => verifyBatchParallel,
|
|
64
|
+
verifyBlsChecksParallel: () => verifyBlsChecksParallel,
|
|
62
65
|
verifySharesBinding: () => verifySharesBinding
|
|
63
66
|
});
|
|
64
67
|
module.exports = __toCommonJS(parallelPool_exports);
|
|
@@ -3739,6 +3742,30 @@ function mapToG2(scalars) {
|
|
|
3739
3742
|
// src/blsUtils.ts
|
|
3740
3743
|
var { longSignatures: ls } = bls12_381;
|
|
3741
3744
|
var ETH2_DST = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
|
|
3745
|
+
function blsAggregatePublicKeys(pubkeys) {
|
|
3746
|
+
if (pubkeys.length === 0) {
|
|
3747
|
+
throw new Error("cannot aggregate empty pubkey set");
|
|
3748
|
+
}
|
|
3749
|
+
return ls.aggregatePublicKeys(pubkeys).toBytes();
|
|
3750
|
+
}
|
|
3751
|
+
function blsVerifyAggregate(pubkeys, message, signature) {
|
|
3752
|
+
try {
|
|
3753
|
+
return ls.verify(
|
|
3754
|
+
signature,
|
|
3755
|
+
ls.hash(message, ETH2_DST),
|
|
3756
|
+
ls.aggregatePublicKeys(pubkeys)
|
|
3757
|
+
);
|
|
3758
|
+
} catch (e) {
|
|
3759
|
+
return false;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
function blsVerifyWithAggregatedPubkey(aggregatedPubkey, message, signature) {
|
|
3763
|
+
try {
|
|
3764
|
+
return ls.verify(signature, ls.hash(message, ETH2_DST), aggregatedPubkey);
|
|
3765
|
+
} catch (e) {
|
|
3766
|
+
return false;
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3742
3769
|
function blsVerifyMultiple(pubkeys, messages, signature) {
|
|
3743
3770
|
try {
|
|
3744
3771
|
if (pubkeys.length !== messages.length) return false;
|
|
@@ -3803,16 +3830,39 @@ function blsVerifyExtraShares(pubshares, threshold, distributedPubkey) {
|
|
|
3803
3830
|
}
|
|
3804
3831
|
}
|
|
3805
3832
|
|
|
3833
|
+
// src/errors.ts
|
|
3834
|
+
var ClusterLockValidationTimeoutError = class _ClusterLockValidationTimeoutError extends Error {
|
|
3835
|
+
/**
|
|
3836
|
+
* @param timeoutMs - Same value as SDK whole-lock validation worker timeout.
|
|
3837
|
+
*/
|
|
3838
|
+
constructor(timeoutMs) {
|
|
3839
|
+
super(
|
|
3840
|
+
`Cluster lock validation exceeded worker time limit (${timeoutMs} ms). Retry later; this does not imply invalid lock data.`
|
|
3841
|
+
);
|
|
3842
|
+
this.timeoutMs = timeoutMs;
|
|
3843
|
+
this.name = "ClusterLockValidationTimeoutError";
|
|
3844
|
+
Object.setPrototypeOf(this, _ClusterLockValidationTimeoutError.prototype);
|
|
3845
|
+
}
|
|
3846
|
+
};
|
|
3847
|
+
|
|
3806
3848
|
// src/verification/parallelPool.ts
|
|
3807
3849
|
var MIN_PARALLEL_VALIDATORS = 50;
|
|
3808
3850
|
var MIN_PARALLEL_BATCH_PAIRS = 100;
|
|
3809
3851
|
var MAX_WORKERS = 8;
|
|
3810
3852
|
var MIN_VALIDATORS_PER_WORKER = 25;
|
|
3811
3853
|
var MIN_PAIRS_PER_WORKER = 50;
|
|
3854
|
+
var MIN_PARALLEL_AGGREGATE_KEYS = 400;
|
|
3855
|
+
var MIN_KEYS_PER_WORKER_AGG = 100;
|
|
3856
|
+
var MIN_VALIDATORS_FOR_VALIDATION_WORKER = 50;
|
|
3857
|
+
var VALIDATION_WORKER_TIMEOUT_MS = 12e4;
|
|
3812
3858
|
var WORKER_TIMEOUT_MS = 6e4;
|
|
3859
|
+
var MAX_CONCURRENT_WORKERS_CAP = 8;
|
|
3860
|
+
function maxConcurrentWorkers(numWorkers) {
|
|
3861
|
+
return Math.min(numWorkers, MAX_CONCURRENT_WORKERS_CAP);
|
|
3862
|
+
}
|
|
3813
3863
|
var workerThreadsCache;
|
|
3814
3864
|
var osCache;
|
|
3815
|
-
var
|
|
3865
|
+
var workerPathByFile = /* @__PURE__ */ new Map();
|
|
3816
3866
|
function loadWorkerThreads() {
|
|
3817
3867
|
if (workerThreadsCache !== void 0) return workerThreadsCache;
|
|
3818
3868
|
try {
|
|
@@ -3831,18 +3881,47 @@ function loadOs() {
|
|
|
3831
3881
|
}
|
|
3832
3882
|
return osCache;
|
|
3833
3883
|
}
|
|
3834
|
-
function getWorkerPath() {
|
|
3835
|
-
|
|
3836
|
-
if (
|
|
3884
|
+
function getWorkerPath(filename) {
|
|
3885
|
+
const cached = workerPathByFile.get(filename);
|
|
3886
|
+
if (cached !== void 0) return cached;
|
|
3887
|
+
if (typeof __dirname === "undefined") {
|
|
3888
|
+
workerPathByFile.set(filename, null);
|
|
3889
|
+
return null;
|
|
3890
|
+
}
|
|
3837
3891
|
const path = require("path");
|
|
3838
|
-
const
|
|
3892
|
+
const fs = require("fs");
|
|
3893
|
+
const candidates = [
|
|
3894
|
+
path.join(__dirname, filename),
|
|
3895
|
+
path.join(__dirname, "verification", filename)
|
|
3896
|
+
];
|
|
3839
3897
|
try {
|
|
3840
|
-
const
|
|
3841
|
-
|
|
3898
|
+
for (const candidate of candidates) {
|
|
3899
|
+
if (fs.existsSync(candidate)) {
|
|
3900
|
+
workerPathByFile.set(filename, candidate);
|
|
3901
|
+
return candidate;
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3842
3904
|
} catch (e) {
|
|
3843
|
-
return workerPathCache = null;
|
|
3844
3905
|
}
|
|
3845
|
-
|
|
3906
|
+
workerPathByFile.set(filename, null);
|
|
3907
|
+
return null;
|
|
3908
|
+
}
|
|
3909
|
+
function mapWithConcurrency(items, concurrency, fn) {
|
|
3910
|
+
return __async(this, null, function* () {
|
|
3911
|
+
const results = new Array(items.length);
|
|
3912
|
+
let next = 0;
|
|
3913
|
+
const runners = Array.from(
|
|
3914
|
+
{ length: Math.min(concurrency, items.length) },
|
|
3915
|
+
() => __async(null, null, function* () {
|
|
3916
|
+
while (next < items.length) {
|
|
3917
|
+
const i = next++;
|
|
3918
|
+
results[i] = yield fn(items[i], i);
|
|
3919
|
+
}
|
|
3920
|
+
})
|
|
3921
|
+
);
|
|
3922
|
+
yield Promise.all(runners);
|
|
3923
|
+
return results;
|
|
3924
|
+
});
|
|
3846
3925
|
}
|
|
3847
3926
|
function chunkArrays(arr, n) {
|
|
3848
3927
|
const size = Math.ceil(arr.length / n);
|
|
@@ -3871,6 +3950,33 @@ function verifySharesSync(shares, distributedKeys, threshold) {
|
|
|
3871
3950
|
}
|
|
3872
3951
|
return true;
|
|
3873
3952
|
}
|
|
3953
|
+
function runWorkerAggregatePubkeys(wt, workerFile, data) {
|
|
3954
|
+
return __async(this, null, function* () {
|
|
3955
|
+
return yield new Promise((resolve) => {
|
|
3956
|
+
let settled = false;
|
|
3957
|
+
const worker = new wt.Worker(workerFile, { workerData: data });
|
|
3958
|
+
const finish = (result) => {
|
|
3959
|
+
if (settled) return;
|
|
3960
|
+
settled = true;
|
|
3961
|
+
clearTimeout(timer);
|
|
3962
|
+
worker.terminate();
|
|
3963
|
+
resolve(result);
|
|
3964
|
+
};
|
|
3965
|
+
const timer = setTimeout(() => {
|
|
3966
|
+
finish(null);
|
|
3967
|
+
}, WORKER_TIMEOUT_MS);
|
|
3968
|
+
worker.once("message", (msg) => {
|
|
3969
|
+
finish(msg instanceof Uint8Array ? msg : null);
|
|
3970
|
+
});
|
|
3971
|
+
worker.once("error", () => {
|
|
3972
|
+
finish(null);
|
|
3973
|
+
});
|
|
3974
|
+
worker.once("exit", (code) => {
|
|
3975
|
+
if (code !== 0) finish(null);
|
|
3976
|
+
});
|
|
3977
|
+
});
|
|
3978
|
+
});
|
|
3979
|
+
}
|
|
3874
3980
|
function runWorker(wt, workerFile, data) {
|
|
3875
3981
|
return __async(this, null, function* () {
|
|
3876
3982
|
return yield new Promise((resolve) => {
|
|
@@ -3901,8 +4007,8 @@ function runWorker(wt, workerFile, data) {
|
|
|
3901
4007
|
function poolSize(itemCount, minPerWorker) {
|
|
3902
4008
|
const wt = loadWorkerThreads();
|
|
3903
4009
|
const os = loadOs();
|
|
3904
|
-
const workerFile = getWorkerPath();
|
|
3905
|
-
const numCpus = os ? os.cpus().length : 1;
|
|
4010
|
+
const workerFile = getWorkerPath("lockWorker.js");
|
|
4011
|
+
const numCpus = os ? Math.max(1, os.cpus().length) : 1;
|
|
3906
4012
|
const numWorkers = Math.min(
|
|
3907
4013
|
MAX_WORKERS,
|
|
3908
4014
|
Math.max(1, Math.floor(itemCount / minPerWorker)),
|
|
@@ -3910,6 +4016,18 @@ function poolSize(itemCount, minPerWorker) {
|
|
|
3910
4016
|
);
|
|
3911
4017
|
return { numWorkers, wt, workerFile };
|
|
3912
4018
|
}
|
|
4019
|
+
function runWorkerChunks(wt, workerFile, chunks) {
|
|
4020
|
+
return __async(this, null, function* () {
|
|
4021
|
+
const results = yield mapWithConcurrency(
|
|
4022
|
+
chunks,
|
|
4023
|
+
maxConcurrentWorkers(chunks.length),
|
|
4024
|
+
(data) => __async(null, null, function* () {
|
|
4025
|
+
return yield runWorker(wt, workerFile, data);
|
|
4026
|
+
})
|
|
4027
|
+
);
|
|
4028
|
+
return results.every(Boolean);
|
|
4029
|
+
});
|
|
4030
|
+
}
|
|
3913
4031
|
function verifySharesBinding(shares, distributedKeys, threshold) {
|
|
3914
4032
|
return __async(this, null, function* () {
|
|
3915
4033
|
if (shares.length !== distributedKeys.length) return false;
|
|
@@ -3923,19 +4041,26 @@ function verifySharesBinding(shares, distributedKeys, threshold) {
|
|
|
3923
4041
|
}
|
|
3924
4042
|
const shareChunks = chunkArrays(shares, numWorkers);
|
|
3925
4043
|
const keyChunks = chunkArrays(distributedKeys, numWorkers);
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
4044
|
+
return yield runWorkerChunks(
|
|
4045
|
+
wt,
|
|
4046
|
+
workerFile,
|
|
4047
|
+
shareChunks.map((chunk, i) => ({
|
|
4048
|
+
mode: "shareBinding",
|
|
4049
|
+
shares: chunk,
|
|
4050
|
+
distributedKeys: keyChunks[i],
|
|
4051
|
+
threshold
|
|
4052
|
+
}))
|
|
4053
|
+
);
|
|
4054
|
+
});
|
|
4055
|
+
}
|
|
4056
|
+
function verifyBlsChecksParallel(checks) {
|
|
4057
|
+
return __async(this, null, function* () {
|
|
4058
|
+
if (checks.length === 0) return true;
|
|
4059
|
+
return yield verifyBatchParallel(
|
|
4060
|
+
checks.map((c) => c.pubkey),
|
|
4061
|
+
checks.map((c) => c.message),
|
|
4062
|
+
checks.map((c) => c.signature)
|
|
3937
4063
|
);
|
|
3938
|
-
return results.every(Boolean);
|
|
3939
4064
|
});
|
|
3940
4065
|
}
|
|
3941
4066
|
function verifyBatchParallel(pubkeys, messages, signatures) {
|
|
@@ -3958,24 +4083,92 @@ function verifyBatchParallel(pubkeys, messages, signatures) {
|
|
|
3958
4083
|
const pkChunks = chunkArrays(pubkeys, numWorkers);
|
|
3959
4084
|
const msgChunks = chunkArrays(messages, numWorkers);
|
|
3960
4085
|
const sigChunks = chunkArrays(signatures, numWorkers);
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
})
|
|
3971
|
-
)
|
|
4086
|
+
return yield runWorkerChunks(
|
|
4087
|
+
wt,
|
|
4088
|
+
workerFile,
|
|
4089
|
+
pkChunks.map((pks, i) => ({
|
|
4090
|
+
mode: "verifyBatch",
|
|
4091
|
+
pubkeys: pks,
|
|
4092
|
+
messages: msgChunks[i],
|
|
4093
|
+
signatures: sigChunks[i]
|
|
4094
|
+
}))
|
|
3972
4095
|
);
|
|
3973
|
-
|
|
4096
|
+
});
|
|
4097
|
+
}
|
|
4098
|
+
function verifyAggregateParallel(pubkeys, message, signature) {
|
|
4099
|
+
return __async(this, null, function* () {
|
|
4100
|
+
if (pubkeys.length === 0) return false;
|
|
4101
|
+
const { numWorkers, wt, workerFile } = poolSize(
|
|
4102
|
+
pubkeys.length,
|
|
4103
|
+
MIN_KEYS_PER_WORKER_AGG
|
|
4104
|
+
);
|
|
4105
|
+
if (wt === null || workerFile === null || pubkeys.length < MIN_PARALLEL_AGGREGATE_KEYS || numWorkers < 2) {
|
|
4106
|
+
return blsVerifyAggregate(pubkeys, message, signature);
|
|
4107
|
+
}
|
|
4108
|
+
const pkChunks = chunkArrays(pubkeys, numWorkers);
|
|
4109
|
+
const partials = yield mapWithConcurrency(
|
|
4110
|
+
pkChunks,
|
|
4111
|
+
maxConcurrentWorkers(pkChunks.length),
|
|
4112
|
+
(chunk) => __async(null, null, function* () {
|
|
4113
|
+
return yield runWorkerAggregatePubkeys(wt, workerFile, {
|
|
4114
|
+
mode: "aggregatePubkeys",
|
|
4115
|
+
pubkeys: chunk
|
|
4116
|
+
});
|
|
4117
|
+
})
|
|
4118
|
+
);
|
|
4119
|
+
if (partials.some((p) => p === null)) return false;
|
|
4120
|
+
const aggregated = blsAggregatePublicKeys(partials);
|
|
4121
|
+
return blsVerifyWithAggregatedPubkey(aggregated, message, signature);
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
function validateClusterLockInWorker(lock, safeRpcUrl) {
|
|
4125
|
+
return __async(this, null, function* () {
|
|
4126
|
+
var _a, _b;
|
|
4127
|
+
const n = (_b = (_a = lock.distributed_validators) == null ? void 0 : _a.length) != null ? _b : 0;
|
|
4128
|
+
if (n < MIN_VALIDATORS_FOR_VALIDATION_WORKER) return null;
|
|
4129
|
+
const wt = loadWorkerThreads();
|
|
4130
|
+
const workerFile = getWorkerPath("clusterLockValidationWorker.js");
|
|
4131
|
+
if (wt === null || workerFile === null) return null;
|
|
4132
|
+
return yield new Promise((resolve, reject) => {
|
|
4133
|
+
let settled = false;
|
|
4134
|
+
const worker = new wt.Worker(workerFile, {
|
|
4135
|
+
workerData: { lock, safeRpcUrl }
|
|
4136
|
+
});
|
|
4137
|
+
let timer;
|
|
4138
|
+
const finish = (result) => {
|
|
4139
|
+
if (settled) return;
|
|
4140
|
+
settled = true;
|
|
4141
|
+
clearTimeout(timer);
|
|
4142
|
+
worker.terminate();
|
|
4143
|
+
resolve(result);
|
|
4144
|
+
};
|
|
4145
|
+
timer = setTimeout(() => {
|
|
4146
|
+
if (settled) return;
|
|
4147
|
+
settled = true;
|
|
4148
|
+
clearTimeout(timer);
|
|
4149
|
+
void worker.terminate();
|
|
4150
|
+
reject(
|
|
4151
|
+
new ClusterLockValidationTimeoutError(VALIDATION_WORKER_TIMEOUT_MS)
|
|
4152
|
+
);
|
|
4153
|
+
}, VALIDATION_WORKER_TIMEOUT_MS);
|
|
4154
|
+
worker.once("message", (msg) => {
|
|
4155
|
+
finish(msg === true);
|
|
4156
|
+
});
|
|
4157
|
+
worker.once("error", () => {
|
|
4158
|
+
finish(null);
|
|
4159
|
+
});
|
|
4160
|
+
worker.once("exit", (code) => {
|
|
4161
|
+
if (code !== 0) finish(null);
|
|
4162
|
+
});
|
|
4163
|
+
});
|
|
3974
4164
|
});
|
|
3975
4165
|
}
|
|
3976
4166
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3977
4167
|
0 && (module.exports = {
|
|
4168
|
+
validateClusterLockInWorker,
|
|
4169
|
+
verifyAggregateParallel,
|
|
3978
4170
|
verifyBatchParallel,
|
|
4171
|
+
verifyBlsChecksParallel,
|
|
3979
4172
|
verifySharesBinding
|
|
3980
4173
|
});
|
|
3981
4174
|
/*! Bundled license information:
|