@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.
Files changed (39) hide show
  1. package/dist/browser/src/index.js +315 -136
  2. package/dist/browser/src/index.js.map +1 -1
  3. package/dist/cjs/src/blsUtils.js +19 -2
  4. package/dist/cjs/src/blsUtils.js.map +1 -1
  5. package/dist/cjs/src/index.js +321 -136
  6. package/dist/cjs/src/index.js.map +1 -1
  7. package/dist/cjs/src/verification/clusterLockValidationWorker.js +14696 -0
  8. package/dist/cjs/src/verification/clusterLockValidationWorker.js.map +1 -0
  9. package/dist/cjs/src/verification/lockWorker.js +13 -1
  10. package/dist/cjs/src/verification/lockWorker.js.map +1 -1
  11. package/dist/cjs/src/verification/parallelPool.js +228 -35
  12. package/dist/cjs/src/verification/parallelPool.js.map +1 -1
  13. package/dist/esm/src/blsUtils.js +7 -3
  14. package/dist/esm/src/chunk-5ASVONSJ.js +10242 -0
  15. package/dist/esm/src/chunk-5ASVONSJ.js.map +1 -0
  16. package/dist/esm/src/{chunk-267HIPEB.js → chunk-LOSYOJC3.js} +16 -1
  17. package/dist/esm/src/{chunk-267HIPEB.js.map → chunk-LOSYOJC3.js.map} +1 -1
  18. package/dist/esm/src/chunk-RYTIXFRX.js +382 -0
  19. package/dist/esm/src/chunk-RYTIXFRX.js.map +1 -0
  20. package/dist/esm/src/index.js +213 -10340
  21. package/dist/esm/src/index.js.map +1 -1
  22. package/dist/esm/src/verification/clusterLockValidationWorker.js +18 -0
  23. package/dist/esm/src/verification/clusterLockValidationWorker.js.map +1 -0
  24. package/dist/esm/src/verification/lockWorker.js +7 -2
  25. package/dist/esm/src/verification/lockWorker.js.map +1 -1
  26. package/dist/esm/src/verification/parallelPool.js +8 -2
  27. package/dist/types/src/blsUtils.d.ts +3 -0
  28. package/dist/types/src/errors.d.ts +13 -0
  29. package/dist/types/src/index.d.ts +1 -1
  30. package/dist/types/src/services.d.ts +4 -1
  31. package/dist/types/src/types.d.ts +6 -0
  32. package/dist/types/src/verification/clusterLockValidationWorker.d.ts +1 -0
  33. package/dist/types/src/verification/common.d.ts +17 -7
  34. package/dist/types/src/verification/lockWorker.d.ts +7 -2
  35. package/dist/types/src/verification/parallelPool.d.ts +9 -0
  36. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  37. package/package.json +1 -1
  38. package/dist/esm/src/chunk-OYZHSNKR.js +0 -186
  39. 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 workerPathCache;
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
- if (workerPathCache !== void 0) return workerPathCache;
3836
- if (typeof __dirname === "undefined") return workerPathCache = null;
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 candidate = path.join(__dirname, "lockWorker.js");
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 fs = require("fs");
3841
- if (!fs.existsSync(candidate)) return workerPathCache = null;
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
- return workerPathCache = candidate;
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
- const results = yield Promise.all(
3927
- shareChunks.map(
3928
- (chunk, i) => __async(null, null, function* () {
3929
- return yield runWorker(wt, workerFile, {
3930
- mode: "shareBinding",
3931
- shares: chunk,
3932
- distributedKeys: keyChunks[i],
3933
- threshold
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
- const results = yield Promise.all(
3962
- pkChunks.map(
3963
- (pks, i) => __async(null, null, function* () {
3964
- return yield runWorker(wt, workerFile, {
3965
- mode: "verifyBatch",
3966
- pubkeys: pks,
3967
- messages: msgChunks[i],
3968
- aggregateSignature: blsAggregateSignatures(sigChunks[i])
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
- return results.every(Boolean);
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: