mirror of
https://github.com/ChainSafe/lodestar.git
synced 2026-01-10 16:18:17 -05:00
feat: switch bls to napi rebuild (#6616)
* chore: update package.json deps and run yarn * feat: remove unused blst config from vitest.browser.*.config.ts * test: move G2@INF test to base blst repo. No longer exported. * fix: add Uint8Array.from for Buffer return value in unit test so type matches for toEqual * refactor: update imports of CoordType to use bls instead of blst * feat: add blsAddVerificationRandomness cli option * feat: add randomBytesNonZero to utils * feat: implement verification randomness for same message * feat: implement napi blst and switch to libuv worker pool * chore: lint * fix: update comments for availableParallelism * feat: set UV_THREADPOOL_SIZE for perf tests * feat: set UV_THREADPOOL_SIZE=$(nproc) in lodestar entrance script * feat: remove case for serialized PublicKey in deserializeSet * feat: add back workBusy count logic to canAcceptWork * feat: automatically set threadpool size in beaconHandler * refactor: rename flag to disableSameMessageVerificationRandomness * fix: remove UV_THREADPOOL_SIZE from ./lodestar * docs: add TODO about updating metrics * fix: make benchmark multi threading cross-compatible * chore: add bls@8.0.0 * feat: default to added randomness * feat: add warning for no same message randomness * fix: passing to updated bls functions * feat: add blst peerDep * fix: default to same message randomness * chore: update yarn.lock * chore: remove unused function to clear lint * feat: break out setThreadPoolSize * docs: update packages/cli/src/cmds/beacon/setThreadPoolSize.ts Co-authored-by: Nico Flaig <nflaig@protonmail.com> * chore: update location for blst dep * chore: run lint again * fix: remove peerDep from light-client * test: fix browser based tests * fix: bad relative imports * docs: add note to readme about switchable bls * docs: typo * chore: lint readme * fix: light-client unit tests * fix: light-client e2e test * feat: remove disableSameMessageVerificationRandomness * refactor: remove unused type * docs: update wordlist * fix: e2e tests * Lint package.json * Revert "fix: e2e tests" This reverts commitf71acd7d6d. * Revert "fix: light-client e2e test" This reverts commit23c11f0a7d. * Revert "fix: light-client unit tests" This reverts commitfa7893ed8e. * Revert "test: fix browser based tests" This reverts commit98d04ab172. * docs: update readme to remove switchable bls argument * fix: replace optimizeDeps in vitest.browser.config * chore: updated to bls 8.1.0 * feat: move setting threadpool size and warnings to applyPreset.ts * fix: remove setThreadpoolSize from beacon handler * feat: move libuv size logging into handler to use logger * refactor: rename applyPreset to preInitialization * refactor: logging about pool size * Update packages/cli/src/options/globalOptions.ts Co-authored-by: Nico Flaig <nflaig@protonmail.com> * refactor: rename prover applyPreset * docs: change comment in cli/index * fix: update logging for * fix: throw error for invalid uvThreadpoolSize * Update packages/cli/src/preInitialization.ts Co-authored-by: Nico Flaig <nflaig@protonmail.com> * Fix lint issues * Remove unused import * refactor: move bls pool logging back to multithread.ts * fix: log of threadcount --------- Co-authored-by: Nico Flaig <nflaig@protonmail.com>
This commit is contained in:
@@ -163,6 +163,7 @@ orchestrator
|
||||
osx
|
||||
overriden
|
||||
params
|
||||
peerDependency
|
||||
pid
|
||||
plaintext
|
||||
pre
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
"test-coverage:e2e": "c8 --config .c8rc.json --report-dir coverage/e2e/ --all npm run test:e2e",
|
||||
"test-coverage:e2e-sim": "c8 --config .c8rc.json --report-dir coverage/e2e-sim/ --all npm run test:e2e:sim",
|
||||
"test-coverage:spec": "c8 --config .c8rc.json --report-dir coverage/spec/ --all npm run test:spec",
|
||||
"benchmark": "yarn benchmark:files 'packages/*/test/perf/**/*.test.ts'",
|
||||
"benchmark:files": "NODE_OPTIONS='--max-old-space-size=4096 --loader=ts-node/esm' benchmark --config .benchrc.yaml --defaultBranch unstable",
|
||||
"benchmark": "UV_THREADPOOL_SIZE=$(node -e 'console.log(require(`os`).availableParallelism())') yarn benchmark:files 'packages/*/test/perf/**/*.test.ts'",
|
||||
"benchmark:files": "UV_THREADPOOL_SIZE=$(node -e 'console.log(require(`os`).availableParallelism())') NODE_OPTIONS='--max-old-space-size=4096 --loader=ts-node/esm' benchmark --config .benchrc.yaml --defaultBranch unstable",
|
||||
"release:create-rc": "node scripts/release/create_rc.mjs",
|
||||
"release:tag-rc": "node scripts/release/tag_rc.mjs",
|
||||
"release:tag-stable": "node scripts/release/tag_stable.mjs",
|
||||
|
||||
@@ -95,8 +95,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/as-sha256": "^0.4.1",
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/blst": "^0.2.10",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/blst": "^1.0.0",
|
||||
"@chainsafe/discv5": "^9.0.0",
|
||||
"@chainsafe/enr": "^3.0.0",
|
||||
"@chainsafe/libp2p-gossipsub": "^11.2.1",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export type {IBlsVerifier} from "./interface.js";
|
||||
export type {BlsMultiThreadWorkerPoolModules, JobQueueItemType} from "./multithread/index.js";
|
||||
export {BlsMultiThreadWorkerPool} from "./multithread/index.js";
|
||||
export type {JobQueueItemType} from "./jobItem.js";
|
||||
export type {BlsMultiThreadWorkerPoolModules} from "./multiThread.js";
|
||||
export {BlsMultiThreadWorkerPool} from "./multiThread.js";
|
||||
export {BlsSingleThreadVerifier} from "./singleThread.js";
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType, PointFormat, PublicKey} from "@chainsafe/bls/types";
|
||||
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
|
||||
import {VerifySignatureOpts} from "../interface.js";
|
||||
import {getAggregatedPubkey} from "../utils.js";
|
||||
import {LinkedList} from "../../../util/array.js";
|
||||
import {Metrics} from "../../../metrics/metrics.js";
|
||||
import {LinkedList} from "../../util/array.js";
|
||||
import {Metrics} from "../../metrics/metrics.js";
|
||||
import {VerifySignatureOpts} from "./interface.js";
|
||||
import {getAggregatedPubkey} from "./utils.js";
|
||||
import {BlsWorkReq} from "./types.js";
|
||||
import {randomBytesNonZero} from "./utils.js";
|
||||
|
||||
export type JobQueueItem = JobQueueItemDefault | JobQueueItemSameMessage;
|
||||
|
||||
@@ -56,7 +57,7 @@ export function jobItemWorkReq(job: JobQueueItem, format: PointFormat, metrics:
|
||||
opts: job.opts,
|
||||
sets: job.sets.map((set) => ({
|
||||
// this can throw, handled in the consumer code
|
||||
publicKey: getAggregatedPubkey(set, metrics).toBytes(format),
|
||||
publicKey: getAggregatedPubkey(set, metrics),
|
||||
signature: set.signature,
|
||||
message: set.signingRoot,
|
||||
})),
|
||||
@@ -73,13 +74,19 @@ export function jobItemWorkReq(job: JobQueueItem, format: PointFormat, metrics:
|
||||
const signatures = job.sets.map((set) => bls.Signature.fromBytes(set.signature, CoordType.affine, true));
|
||||
timer?.();
|
||||
|
||||
// adding verification randomness is napi specific. must not attempt with herumi until
|
||||
// @chainsafe/bls is updated to support it with herumi
|
||||
const randomness: Uint8Array[] = [];
|
||||
for (let i = 0; i < job.sets.length; i++) {
|
||||
randomness.push(randomBytesNonZero(8));
|
||||
}
|
||||
return {
|
||||
opts: job.opts,
|
||||
sets: [
|
||||
{
|
||||
publicKey: bls.PublicKey.aggregate(job.sets.map((set) => set.publicKey)).toBytes(format),
|
||||
signature: bls.Signature.aggregate(signatures).toBytes(format),
|
||||
message: job.message,
|
||||
publicKey: bls.PublicKey.aggregate(job.sets.map((set, i) => set.publicKey.multiplyBy(randomness[i]))),
|
||||
signature: bls.Signature.aggregate(signatures.map((sig, i) => sig.multiplyBy(randomness[i]))),
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
import {CoordType, PublicKey} from "@chainsafe/bls/types";
|
||||
import bls from "@chainsafe/bls";
|
||||
|
||||
const MIN_SET_COUNT_TO_BATCH = 2;
|
||||
|
||||
export type SignatureSetDeserialized = {
|
||||
publicKey: PublicKey;
|
||||
message: Uint8Array;
|
||||
signature: Uint8Array;
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify signatures sets with batch verification or regular core verify depending on the set count.
|
||||
* Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
|
||||
*/
|
||||
export function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean {
|
||||
try {
|
||||
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
|
||||
return bls.Signature.verifyMultipleSignatures(
|
||||
sets.map((s) => ({
|
||||
publicKey: s.publicKey,
|
||||
message: s.message,
|
||||
// true = validate signature
|
||||
signature: bls.Signature.fromBytes(s.signature, CoordType.affine, true),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
// .every on an empty array returns true
|
||||
if (sets.length === 0) {
|
||||
throw Error("Empty signature set");
|
||||
}
|
||||
|
||||
// If too few signature sets verify them without batching
|
||||
return sets.every((set) => {
|
||||
// true = validate signature
|
||||
const sig = bls.Signature.fromBytes(set.signature, CoordType.affine, true);
|
||||
return sig.verify(set.publicKey, set.message);
|
||||
});
|
||||
} catch (_) {
|
||||
// A signature could be malformed, in that case fromBytes throws error
|
||||
// blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
|
||||
// see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,17 @@
|
||||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
import path from "node:path";
|
||||
import {spawn, Worker} from "@chainsafe/threads";
|
||||
// `threads` library creates self global variable which breaks `timeout-abort-controller` https://github.com/jacobheun/timeout-abort-controller/issues/9
|
||||
// Don't add an eslint disable here as a reminder that this has to be fixed eventually
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line
|
||||
self = undefined;
|
||||
import os from "node:os";
|
||||
import bls from "@chainsafe/bls";
|
||||
import {Implementation, PointFormat, PublicKey} from "@chainsafe/bls/types";
|
||||
import {PointFormat, PublicKey} from "@chainsafe/bls/types";
|
||||
import {Logger} from "@lodestar/utils";
|
||||
import {ISignatureSet} from "@lodestar/state-transition";
|
||||
import {QueueError, QueueErrorCode} from "../../../util/queue/index.js";
|
||||
import {Metrics} from "../../../metrics/index.js";
|
||||
import {IBlsVerifier, VerifySignatureOpts} from "../interface.js";
|
||||
import {getAggregatedPubkey, getAggregatedPubkeysCount} from "../utils.js";
|
||||
import {verifySignatureSetsMaybeBatch} from "../maybeBatch.js";
|
||||
import {LinkedList} from "../../../util/array.js";
|
||||
import {BlsWorkReq, BlsWorkResult, WorkerData, WorkResultCode, WorkResultError} from "./types.js";
|
||||
import {QueueError, QueueErrorCode} from "../../util/queue/index.js";
|
||||
import {Metrics} from "../../metrics/index.js";
|
||||
import {LinkedList} from "../../util/array.js";
|
||||
import {IBlsVerifier, VerifySignatureOpts} from "./interface.js";
|
||||
import {getAggregatedPubkey, getAggregatedPubkeysCount, getJobResultError} from "./utils.js";
|
||||
import {verifySets} from "./verifySets.js";
|
||||
import {BlsWorkReq, WorkResultCode} from "./types.js";
|
||||
import {chunkifyMaximizeChunkSize} from "./utils.js";
|
||||
import {defaultPoolSize} from "./poolSize.js";
|
||||
import {runBlsWorkReq} from "./runBlsWorkReq.js";
|
||||
import {
|
||||
JobQueueItem,
|
||||
JobQueueItemSameMessage,
|
||||
@@ -29,9 +21,6 @@ import {
|
||||
jobItemWorkReq,
|
||||
} from "./jobItem.js";
|
||||
|
||||
// Worker constructor consider the path relative to the current working directory
|
||||
const workerDir = process.env.NODE_ENV === "test" ? "../../../../lib/chain/bls/multithread" : "./";
|
||||
|
||||
export type BlsMultiThreadWorkerPoolModules = {
|
||||
logger: Logger;
|
||||
metrics: Metrics | null;
|
||||
@@ -41,11 +30,6 @@ export type BlsMultiThreadWorkerPoolOptions = {
|
||||
blsVerifyAllMultiThread?: boolean;
|
||||
};
|
||||
|
||||
export type {JobQueueItemType};
|
||||
|
||||
// 1 worker for the main thread
|
||||
const blsPoolSize = Math.max(defaultPoolSize - 1, 1);
|
||||
|
||||
/**
|
||||
* Split big signature sets into smaller sets so they can be sent to multiple workers.
|
||||
*
|
||||
@@ -79,30 +63,6 @@ const MAX_BUFFER_WAIT_MS = 100;
|
||||
*/
|
||||
const MAX_JOBS_CAN_ACCEPT_WORK = 512;
|
||||
|
||||
type WorkerApi = {
|
||||
verifyManySignatureSets(workReqArr: BlsWorkReq[]): Promise<BlsWorkResult>;
|
||||
};
|
||||
|
||||
enum WorkerStatusCode {
|
||||
notInitialized,
|
||||
initializing,
|
||||
initializationError,
|
||||
idle,
|
||||
running,
|
||||
}
|
||||
|
||||
type WorkerStatus =
|
||||
| {code: WorkerStatusCode.notInitialized}
|
||||
| {code: WorkerStatusCode.initializing; initPromise: Promise<WorkerApi>}
|
||||
| {code: WorkerStatusCode.initializationError; error: Error}
|
||||
| {code: WorkerStatusCode.idle; workerApi: WorkerApi}
|
||||
| {code: WorkerStatusCode.running; workerApi: WorkerApi};
|
||||
|
||||
type WorkerDescriptor = {
|
||||
worker: Worker;
|
||||
status: WorkerStatus;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps "threads" library thread pool queue system with the goals:
|
||||
* - Complete total outstanding jobs in total minimum time possible.
|
||||
@@ -115,8 +75,11 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
private readonly logger: Logger;
|
||||
private readonly metrics: Metrics | null;
|
||||
|
||||
private readonly format: PointFormat;
|
||||
private readonly workers: WorkerDescriptor[];
|
||||
private readonly format = PointFormat.uncompressed;
|
||||
|
||||
private blsPoolSize: number;
|
||||
private workersBusy = 0;
|
||||
|
||||
private readonly jobs = new LinkedList<JobQueueItem>();
|
||||
private bufferedJobs: {
|
||||
jobs: LinkedList<JobQueueItem>;
|
||||
@@ -127,34 +90,43 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
} | null = null;
|
||||
private blsVerifyAllMultiThread: boolean;
|
||||
private closed = false;
|
||||
private workersBusy = 0;
|
||||
|
||||
constructor(options: BlsMultiThreadWorkerPoolOptions, modules: BlsMultiThreadWorkerPoolModules) {
|
||||
const {logger, metrics} = modules;
|
||||
this.logger = logger;
|
||||
this.metrics = metrics;
|
||||
if (bls.implementation === "herumi") {
|
||||
throw new Error("Herumi BLS implementation is not supported");
|
||||
}
|
||||
|
||||
this.logger = modules.logger;
|
||||
this.blsVerifyAllMultiThread = options.blsVerifyAllMultiThread ?? false;
|
||||
|
||||
// TODO: Allow to customize implementation
|
||||
const implementation = bls.implementation;
|
||||
|
||||
// Use compressed for herumi for now.
|
||||
// THe worker is not able to deserialize from uncompressed
|
||||
// `Error: err _wrapDeserialize`
|
||||
this.format = implementation === "blst-native" ? PointFormat.uncompressed : PointFormat.compressed;
|
||||
this.workers = this.createWorkers(implementation, blsPoolSize);
|
||||
this.blsPoolSize = Number(process.env.UV_THREADPOOL_SIZE);
|
||||
const defaultThreadpoolSize = os.availableParallelism();
|
||||
this.logger.info(`BLS libuv pool size: ${this.blsPoolSize}`);
|
||||
/**
|
||||
* Help users ensure that thread pool is large enough for optimal performance
|
||||
*
|
||||
* Node reports available CPUs. There is enough idle time on the main and
|
||||
* network threads that setting UV_THREADPOOL_SIZE to $(nproc) provides the
|
||||
* best performance. Recommend this value to consumers
|
||||
*/
|
||||
if (this.blsPoolSize < defaultThreadpoolSize) {
|
||||
this.logger.warn(
|
||||
`UV_THREADPOOL_SIZE=${this.blsPoolSize} which is less than available CPUs: ${defaultThreadpoolSize}. This will cause performance degradation.`
|
||||
);
|
||||
}
|
||||
|
||||
const {metrics} = modules;
|
||||
this.metrics = metrics;
|
||||
if (metrics) {
|
||||
metrics.blsThreadPool.queueLength.addCollect(() => {
|
||||
metrics.blsThreadPool.queueLength.set(this.jobs.length);
|
||||
metrics.blsThreadPool.workersBusy.set(this.workersBusy);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
canAcceptWork(): boolean {
|
||||
return (
|
||||
this.workersBusy < blsPoolSize &&
|
||||
this.workersBusy < this.blsPoolSize &&
|
||||
// TODO: Should also bound the jobs queue?
|
||||
this.jobs.length < MAX_JOBS_CAN_ACCEPT_WORK
|
||||
);
|
||||
@@ -173,17 +145,15 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
|
||||
if (opts.verifyOnMainThread && !this.blsVerifyAllMultiThread) {
|
||||
const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer();
|
||||
try {
|
||||
return verifySignatureSetsMaybeBatch(
|
||||
sets.map((set) => ({
|
||||
publicKey: getAggregatedPubkey(set),
|
||||
message: set.signingRoot.valueOf(),
|
||||
signature: set.signature,
|
||||
}))
|
||||
);
|
||||
} finally {
|
||||
if (timer) timer();
|
||||
}
|
||||
const isValid = verifySets(
|
||||
sets.map((set) => ({
|
||||
publicKey: getAggregatedPubkey(set),
|
||||
message: set.signingRoot.valueOf(),
|
||||
signature: set.signature,
|
||||
}))
|
||||
);
|
||||
timer?.();
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Split large array of sets into smaller.
|
||||
@@ -250,56 +220,8 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
for (const job of this.jobs) {
|
||||
job.reject(new QueueError({code: QueueErrorCode.QUEUE_ABORTED}));
|
||||
}
|
||||
|
||||
this.jobs.clear();
|
||||
|
||||
// Terminate all workers. await to ensure no workers are left hanging
|
||||
await Promise.all(
|
||||
Array.from(this.workers.entries()).map(([id, worker]) =>
|
||||
// NOTE: 'threads' has not yet updated types, and NodeJS complains with
|
||||
// [DEP0132] DeprecationWarning: Passing a callback to worker.terminate() is deprecated. It returns a Promise instead.
|
||||
(worker.worker.terminate() as unknown as Promise<void>).catch((e: Error) => {
|
||||
this.logger.error("Error terminating worker", {id}, e);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private createWorkers(implementation: Implementation, poolSize: number): WorkerDescriptor[] {
|
||||
const workers: WorkerDescriptor[] = [];
|
||||
|
||||
for (let i = 0; i < poolSize; i++) {
|
||||
const workerData: WorkerData = {implementation, workerId: i};
|
||||
const worker = new Worker(path.join(workerDir, "worker.js"), {
|
||||
workerData,
|
||||
} as ConstructorParameters<typeof Worker>[1]);
|
||||
|
||||
const workerDescriptor: WorkerDescriptor = {
|
||||
worker,
|
||||
status: {code: WorkerStatusCode.notInitialized},
|
||||
};
|
||||
workers.push(workerDescriptor);
|
||||
|
||||
// TODO: Consider initializing only when necessary
|
||||
const initPromise = spawn<WorkerApi>(worker, {
|
||||
// A Lodestar Node may do very expensive task at start blocking the event loop and causing
|
||||
// the initialization to timeout. The number below is big enough to almost disable the timeout
|
||||
timeout: 5 * 60 * 1000,
|
||||
});
|
||||
|
||||
workerDescriptor.status = {code: WorkerStatusCode.initializing, initPromise};
|
||||
|
||||
initPromise
|
||||
.then((workerApi) => {
|
||||
workerDescriptor.status = {code: WorkerStatusCode.idle, workerApi};
|
||||
// Potentially run jobs that were queued before initialization of the first worker
|
||||
setTimeout(this.runJob, 0);
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
workerDescriptor.status = {code: WorkerStatusCode.initializationError, error};
|
||||
});
|
||||
}
|
||||
|
||||
return workers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,18 +232,6 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
throw new QueueError({code: QueueErrorCode.QUEUE_ABORTED});
|
||||
}
|
||||
|
||||
// TODO: Consider if limiting queue size is necessary here.
|
||||
// It would be bad to reject signatures because the node is slow.
|
||||
// However, if the worker communication broke jobs won't ever finish
|
||||
|
||||
if (
|
||||
this.workers.length > 0 &&
|
||||
this.workers[0].status.code === WorkerStatusCode.initializationError &&
|
||||
this.workers.every((worker) => worker.status.code === WorkerStatusCode.initializationError)
|
||||
) {
|
||||
return job.reject(this.workers[0].status.error);
|
||||
}
|
||||
|
||||
// Append batchable sets to `bufferedJobs`, starting a timeout to push them into `jobs`.
|
||||
// Do not call `runJob()`, it is called from `runBufferedJobs()`
|
||||
if (job.opts.batchable) {
|
||||
@@ -364,24 +274,12 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find idle worker
|
||||
const worker = this.workers.find((worker) => worker.status.code === WorkerStatusCode.idle);
|
||||
if (!worker || worker.status.code !== WorkerStatusCode.idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare work package
|
||||
const jobsInput = this.prepareWork();
|
||||
if (jobsInput.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: After sending the work to the worker the main thread can drop the job arguments
|
||||
// and free-up memory, only needs to keep the job's Promise handlers.
|
||||
// Maybe it's not useful since all data referenced in jobs is likely referenced by others
|
||||
|
||||
const workerApi = worker.status.workerApi;
|
||||
worker.status = {code: WorkerStatusCode.running, workerApi};
|
||||
this.workersBusy++;
|
||||
|
||||
try {
|
||||
@@ -441,9 +339,9 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
// Only downside is the job promise may be resolved twice, but that's not an issue
|
||||
|
||||
const [jobStartSec, jobStartNs] = process.hrtime();
|
||||
const workResult = await workerApi.verifyManySignatureSets(workReqs);
|
||||
const workResult = await runBlsWorkReq(workReqs);
|
||||
const [jobEndSec, jobEndNs] = process.hrtime();
|
||||
const {workerId, batchRetries, batchSigsSuccess, workerStartTime, workerEndTime, results} = workResult;
|
||||
const {batchRetries, batchSigsSuccess, workerStartTime, workerEndTime, results} = workResult;
|
||||
|
||||
const [workerStartSec, workerStartNs] = workerStartTime;
|
||||
const [workerEndSec, workerEndNs] = workerEndTime;
|
||||
@@ -460,7 +358,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
// TODO: enable exhaustive switch case checks lint rule
|
||||
switch (job.type) {
|
||||
case JobQueueItemType.default:
|
||||
if (!jobResult || jobResult.code !== WorkResultCode.success) {
|
||||
if (jobResult.code !== WorkResultCode.success) {
|
||||
job.reject(getJobResultError(jobResult, i));
|
||||
errorCount += sigSetCount;
|
||||
} else {
|
||||
@@ -471,7 +369,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
|
||||
// handle result of the verification of aggregated signature against aggregated pubkeys
|
||||
case JobQueueItemType.sameMessage:
|
||||
if (!jobResult || jobResult.code !== WorkResultCode.success) {
|
||||
if (jobResult.code !== WorkResultCode.success) {
|
||||
job.reject(getJobResultError(jobResult, i));
|
||||
errorCount += 1;
|
||||
} else {
|
||||
@@ -488,12 +386,13 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: (@matthewkeil) all of these metrics need to be revisited
|
||||
const workerJobTimeSec = workerEndSec - workerStartSec + (workerEndNs - workerStartNs) / 1e9;
|
||||
const latencyToWorkerSec = workerStartSec - jobStartSec + (workerStartNs - jobStartNs) / 1e9;
|
||||
const latencyFromWorkerSec = jobEndSec - workerEndSec + Number(jobEndNs - workerEndNs) / 1e9;
|
||||
|
||||
this.metrics?.blsThreadPool.timePerSigSet.observe(workerJobTimeSec / startedSigSets);
|
||||
this.metrics?.blsThreadPool.jobsWorkerTime.inc({workerId}, workerJobTimeSec);
|
||||
this.metrics?.blsThreadPool.jobsWorkerTime.inc({workerId: 0}, workerJobTimeSec);
|
||||
this.metrics?.blsThreadPool.latencyToWorker.observe(latencyToWorkerSec);
|
||||
this.metrics?.blsThreadPool.latencyFromWorker.observe(latencyFromWorkerSec);
|
||||
this.metrics?.blsThreadPool.successJobsSignatureSetsCount.inc(successCount);
|
||||
@@ -511,7 +410,6 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
worker.status = {code: WorkerStatusCode.idle, workerApi};
|
||||
this.workersBusy--;
|
||||
|
||||
// Potentially run a new job
|
||||
@@ -566,21 +464,4 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
|
||||
this.metrics?.blsThreadPool.sameMessageRetryJobs.inc(1);
|
||||
this.metrics?.blsThreadPool.sameMessageRetrySets.inc(job.sets.length);
|
||||
}
|
||||
|
||||
/** For testing */
|
||||
private async waitTillInitialized(): Promise<void> {
|
||||
await Promise.all(
|
||||
this.workers.map(async (worker) => {
|
||||
if (worker.status.code === WorkerStatusCode.initializing) {
|
||||
await worker.status.initPromise;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getJobResultError(jobResult: WorkResultError | null, i: number): Error {
|
||||
const workerError = jobResult ? Error(jobResult.error.message) : Error(`No jobResult for index ${i}`);
|
||||
if (jobResult?.error?.stack) workerError.stack = jobResult.error.stack;
|
||||
return workerError;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
let defaultPoolSize: number;
|
||||
|
||||
try {
|
||||
if (typeof navigator !== "undefined") {
|
||||
defaultPoolSize = navigator.hardwareConcurrency ?? 4;
|
||||
} else {
|
||||
defaultPoolSize = (await import("node:os")).availableParallelism();
|
||||
}
|
||||
} catch (e) {
|
||||
defaultPoolSize = 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-platform aprox number of logical cores
|
||||
*/
|
||||
export {defaultPoolSize};
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Splits an array into an array of arrays maximizing the size of the smallest chunk.
|
||||
*/
|
||||
export function chunkifyMaximizeChunkSize<T>(arr: T[], minPerChunk: number): T[][] {
|
||||
const chunkCount = Math.floor(arr.length / minPerChunk);
|
||||
if (chunkCount <= 1) {
|
||||
return [arr];
|
||||
}
|
||||
|
||||
// Prefer less chunks of bigger size
|
||||
const perChunk = Math.ceil(arr.length / chunkCount);
|
||||
const arrArr: T[][] = [];
|
||||
|
||||
for (let i = 0; i < arr.length; i += perChunk) {
|
||||
arrArr.push(arr.slice(i, i + perChunk));
|
||||
}
|
||||
|
||||
return arrArr;
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
import worker from "node:worker_threads";
|
||||
import {expose} from "@chainsafe/threads/worker";
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/bls/types";
|
||||
import {verifySignatureSetsMaybeBatch, SignatureSetDeserialized} from "../maybeBatch.js";
|
||||
import {WorkerData, BlsWorkReq, WorkResult, WorkResultCode, SerializedSet, BlsWorkResult} from "./types.js";
|
||||
import {asyncVerifySets} from "./verifySets.js";
|
||||
import {chunkifyMaximizeChunkSize} from "./utils.js";
|
||||
import {BlsWorkReq, WorkResult, WorkResultCode, WorkRequestSet, BlsWorkResult} from "./types.js";
|
||||
|
||||
/**
|
||||
* Split batchable sets in chunks of minimum size 16.
|
||||
@@ -16,36 +11,23 @@ import {chunkifyMaximizeChunkSize} from "./utils.js";
|
||||
*/
|
||||
const BATCHABLE_MIN_PER_CHUNK = 16;
|
||||
|
||||
// Cloned data from instatiation
|
||||
const workerData = worker.workerData as WorkerData;
|
||||
if (!workerData) throw Error("workerData must be defined");
|
||||
const {workerId} = workerData || {};
|
||||
|
||||
expose({
|
||||
async verifyManySignatureSets(workReqArr: BlsWorkReq[]): Promise<BlsWorkResult> {
|
||||
return verifyManySignatureSets(workReqArr);
|
||||
},
|
||||
});
|
||||
|
||||
function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
export async function runBlsWorkReq(workReqArr: BlsWorkReq[]): Promise<BlsWorkResult> {
|
||||
const [startSec, startNs] = process.hrtime();
|
||||
const results: WorkResult<boolean>[] = [];
|
||||
let batchRetries = 0;
|
||||
let batchSigsSuccess = 0;
|
||||
|
||||
// If there are multiple batchable sets attempt batch verification with them
|
||||
const batchableSets: {idx: number; sets: SignatureSetDeserialized[]}[] = [];
|
||||
const nonBatchableSets: {idx: number; sets: SignatureSetDeserialized[]}[] = [];
|
||||
const batchableSets: {idx: number; sets: WorkRequestSet[]}[] = [];
|
||||
const nonBatchableSets: {idx: number; sets: WorkRequestSet[]}[] = [];
|
||||
|
||||
// Split sets between batchable and non-batchable preserving their original index in the req array
|
||||
for (let i = 0; i < workReqArr.length; i++) {
|
||||
const workReq = workReqArr[i];
|
||||
const sets = workReq.sets.map(deserializeSet);
|
||||
|
||||
if (workReq.opts.batchable) {
|
||||
batchableSets.push({idx: i, sets});
|
||||
batchableSets.push({idx: i, sets: workReq.sets});
|
||||
} else {
|
||||
nonBatchableSets.push({idx: i, sets});
|
||||
nonBatchableSets.push({idx: i, sets: workReq.sets});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +36,7 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
const batchableChunks = chunkifyMaximizeChunkSize(batchableSets, BATCHABLE_MIN_PER_CHUNK);
|
||||
|
||||
for (const batchableChunk of batchableChunks) {
|
||||
const allSets: SignatureSetDeserialized[] = [];
|
||||
const allSets: WorkRequestSet[] = [];
|
||||
for (const {sets} of batchableChunk) {
|
||||
for (const set of sets) {
|
||||
allSets.push(set);
|
||||
@@ -63,7 +45,7 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
|
||||
try {
|
||||
// Attempt to verify multiple sets at once
|
||||
const isValid = verifySignatureSetsMaybeBatch(allSets);
|
||||
const isValid = await asyncVerifySets(allSets);
|
||||
|
||||
if (isValid) {
|
||||
// The entire batch is valid, return success to all
|
||||
@@ -88,7 +70,7 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
|
||||
for (const {idx, sets} of nonBatchableSets) {
|
||||
try {
|
||||
const isValid = verifySignatureSetsMaybeBatch(sets);
|
||||
const isValid = await asyncVerifySets(sets);
|
||||
results[idx] = {code: WorkResultCode.success, result: isValid};
|
||||
} catch (e) {
|
||||
results[idx] = {code: WorkResultCode.error, error: e as Error};
|
||||
@@ -97,8 +79,8 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
|
||||
const [workerEndSec, workerEndNs] = process.hrtime();
|
||||
|
||||
// TODO: (@matthewkeil) all of these metrics need to be revisited
|
||||
return {
|
||||
workerId,
|
||||
batchRetries,
|
||||
batchSigsSuccess,
|
||||
workerStartTime: [startSec, startNs],
|
||||
@@ -106,11 +88,3 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult {
|
||||
results,
|
||||
};
|
||||
}
|
||||
|
||||
function deserializeSet(set: SerializedSet): SignatureSetDeserialized {
|
||||
return {
|
||||
publicKey: bls.PublicKey.fromBytes(set.publicKey, CoordType.affine),
|
||||
message: set.message,
|
||||
signature: set.signature,
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import {PublicKey, Signature} from "@chainsafe/bls/types";
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/blst";
|
||||
import {CoordType} from "@chainsafe/bls/types";
|
||||
import {ISignatureSet} from "@lodestar/state-transition";
|
||||
import {Metrics} from "../../metrics/index.js";
|
||||
import {IBlsVerifier} from "./interface.js";
|
||||
import {verifySignatureSetsMaybeBatch} from "./maybeBatch.js";
|
||||
import {verifySets} from "./verifySets.js";
|
||||
import {getAggregatedPubkey, getAggregatedPubkeysCount} from "./utils.js";
|
||||
|
||||
export class BlsSingleThreadVerifier implements IBlsVerifier {
|
||||
@@ -25,7 +25,7 @@ export class BlsSingleThreadVerifier implements IBlsVerifier {
|
||||
|
||||
// Count time after aggregating
|
||||
const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer();
|
||||
const isValid = verifySignatureSetsMaybeBatch(setsAggregated);
|
||||
const isValid = verifySets(setsAggregated);
|
||||
|
||||
// Don't use a try/catch, only count run without exceptions
|
||||
if (timer) {
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import {VerifySignatureOpts} from "../interface.js";
|
||||
import {PublicKey, Signature} from "@chainsafe/bls/types";
|
||||
import {VerifySignatureOpts} from "./interface.js";
|
||||
|
||||
export type WorkerData = {
|
||||
implementation: "herumi" | "blst-native";
|
||||
workerId: number;
|
||||
};
|
||||
|
||||
export type SerializedSet = {
|
||||
publicKey: Uint8Array;
|
||||
export type DeserializedKeySet = {
|
||||
publicKey: PublicKey;
|
||||
message: Uint8Array;
|
||||
signature: Uint8Array;
|
||||
};
|
||||
|
||||
export type DeserializedSet = {
|
||||
publicKey: PublicKey;
|
||||
message: Uint8Array;
|
||||
signature: Signature;
|
||||
};
|
||||
|
||||
export type WorkRequestSet = DeserializedKeySet | DeserializedSet;
|
||||
|
||||
export type BlsWorkReq = {
|
||||
opts: VerifySignatureOpts;
|
||||
sets: SerializedSet[];
|
||||
sets: WorkRequestSet[];
|
||||
};
|
||||
|
||||
export enum WorkResultCode {
|
||||
@@ -25,8 +29,6 @@ export type WorkResultError = {code: WorkResultCode.error; error: Error};
|
||||
export type WorkResult<R> = {code: WorkResultCode.success; result: R} | WorkResultError;
|
||||
|
||||
export type BlsWorkResult = {
|
||||
/** Ascending integer identifying the worker for metrics */
|
||||
workerId: number;
|
||||
/** Total num of batches that had to be retried */
|
||||
batchRetries: number;
|
||||
/** Total num of sigs that have been successfully verified with batching */
|
||||
@@ -1,7 +1,8 @@
|
||||
import type {PublicKey} from "@chainsafe/bls/types";
|
||||
import bls from "@chainsafe/bls";
|
||||
import {PublicKey} from "@chainsafe/bls/types";
|
||||
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
|
||||
import {Metrics} from "../../metrics/metrics.js";
|
||||
import {WorkResultError} from "./types.js";
|
||||
|
||||
export function getAggregatedPubkey(signatureSet: ISignatureSet, metrics: Metrics | null = null): PublicKey {
|
||||
switch (signatureSet.type) {
|
||||
@@ -29,3 +30,42 @@ export function getAggregatedPubkeysCount(signatureSets: ISignatureSet[]): numbe
|
||||
}
|
||||
return pubkeysConut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits an array into an array of arrays maximizing the size of the smallest chunk.
|
||||
*/
|
||||
export function chunkifyMaximizeChunkSize<T>(arr: T[], minPerChunk: number): T[][] {
|
||||
const chunkCount = Math.floor(arr.length / minPerChunk);
|
||||
if (chunkCount <= 1) {
|
||||
return [arr];
|
||||
}
|
||||
|
||||
// Prefer less chunks of bigger size
|
||||
const perChunk = Math.ceil(arr.length / chunkCount);
|
||||
const arrArr: T[][] = [];
|
||||
|
||||
for (let i = 0; i < arr.length; i += perChunk) {
|
||||
arrArr.push(arr.slice(i, i + perChunk));
|
||||
}
|
||||
|
||||
return arrArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* `rand` must not be exactly zero. Otherwise it would allow the verification of invalid signatures
|
||||
* See https://github.com/ChainSafe/blst-ts/issues/45
|
||||
*/
|
||||
export function randomBytesNonZero(bytesCount: number): Uint8Array {
|
||||
const rand = crypto.getRandomValues(new Uint8Array(bytesCount));
|
||||
for (let i = 0; i < bytesCount; i++) {
|
||||
if (rand[i] !== 0) return rand;
|
||||
}
|
||||
rand[0] = 1;
|
||||
return rand;
|
||||
}
|
||||
|
||||
export function getJobResultError(jobResult: WorkResultError | null, i: number): Error {
|
||||
const workerError = jobResult ? Error(jobResult.error.message) : Error(`No jobResult for index ${i}`);
|
||||
if (jobResult?.error?.stack) workerError.stack = jobResult.error.stack;
|
||||
return workerError;
|
||||
}
|
||||
|
||||
53
packages/beacon-node/src/chain/bls/verifySets.ts
Normal file
53
packages/beacon-node/src/chain/bls/verifySets.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {WorkRequestSet} from "./types.js";
|
||||
|
||||
const MIN_SET_COUNT_TO_BATCH = 2;
|
||||
|
||||
/**
|
||||
* Verify signatures sets with batch verification or regular core verify depending on the set count.
|
||||
* Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
|
||||
*/
|
||||
export function verifySets(sets: WorkRequestSet[]): boolean {
|
||||
try {
|
||||
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
|
||||
return bls.verifyMultipleSignatures(sets);
|
||||
}
|
||||
|
||||
// .every on an empty array returns true
|
||||
if (sets.length === 0) {
|
||||
throw Error("Empty signature set");
|
||||
}
|
||||
|
||||
// If too few signature sets verify them without batching
|
||||
return sets.every(({message, publicKey, signature}) => bls.verify(publicKey, message, signature));
|
||||
} catch (_) {
|
||||
// A signature could be malformed, in that case fromBytes throws error
|
||||
// blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
|
||||
// see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function asyncVerifySets(sets: WorkRequestSet[]): Promise<boolean> {
|
||||
try {
|
||||
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
|
||||
return await bls.asyncVerifyMultipleSignatures(sets);
|
||||
}
|
||||
|
||||
// .every on an empty array returns true
|
||||
if (sets.length === 0) {
|
||||
throw Error("Empty signature sets");
|
||||
}
|
||||
|
||||
const promises = await Promise.all(
|
||||
sets.map(({message, publicKey, signature}) => bls.asyncVerify(publicKey, message, signature))
|
||||
);
|
||||
// If too few signature sets verify them without batching
|
||||
return promises.every((isValid) => isValid);
|
||||
} catch (_) {
|
||||
// A signature could be malformed, in that case fromBytes throws error
|
||||
// blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
|
||||
// see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import {describe, it, beforeAll, expect, beforeEach, afterEach} from "vitest";
|
||||
import bls from "@chainsafe/bls";
|
||||
import {PublicKey} from "@chainsafe/bls/types";
|
||||
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
|
||||
import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/index.js";
|
||||
import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/index.js";
|
||||
import {testLogger} from "../../../utils/logger.js";
|
||||
import {VerifySignatureOpts} from "../../../../src/chain/bls/interface.js";
|
||||
|
||||
@@ -50,8 +50,6 @@ describe("chain / bls / multithread queue", function () {
|
||||
const pool = new BlsMultiThreadWorkerPool({}, {logger, metrics: null});
|
||||
// await terminating all workers
|
||||
afterEachCallbacks.push(() => pool.close());
|
||||
// Wait until initialized
|
||||
await pool["waitTillInitialized"]();
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/blst";
|
||||
import {PublicKey} from "@chainsafe/bls/types";
|
||||
import {CoordType, PublicKey} from "@chainsafe/bls/types";
|
||||
import {describe, it, expect, beforeEach} from "vitest";
|
||||
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
|
||||
import {BlsSingleThreadVerifier} from "../../../../src/chain/bls/singleThread.js";
|
||||
import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/index.js";
|
||||
import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/index.js";
|
||||
import {testLogger} from "../../../utils/logger.js";
|
||||
|
||||
describe("BlsVerifier ", function () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {chunkifyMaximizeChunkSize} from "../../../../src/chain/bls/multithread/utils.js";
|
||||
import {chunkifyMaximizeChunkSize} from "../../../../src/chain/bls/utils.js";
|
||||
import {linspace} from "../../../../src/util/numpy.js";
|
||||
|
||||
describe("chain / bls / utils / chunkifyMaximizeChunkSize", () => {
|
||||
|
||||
@@ -51,10 +51,10 @@
|
||||
"blockchain"
|
||||
],
|
||||
"dependencies": {
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/blst": "^1.0.0",
|
||||
"@chainsafe/bls-keygen": "^0.4.0",
|
||||
"@chainsafe/bls-keystore": "^3.0.1",
|
||||
"@chainsafe/blst": "^0.2.10",
|
||||
"@chainsafe/discv5": "^9.0.0",
|
||||
"@chainsafe/enr": "^3.0.0",
|
||||
"@chainsafe/persistent-merkle-tree": "^0.7.1",
|
||||
|
||||
@@ -43,6 +43,7 @@ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise<void
|
||||
const abortController = new AbortController();
|
||||
|
||||
logger.info("Lodestar", {network, version, commit});
|
||||
|
||||
// Callback for beacon to request forced exit, for e.g. in case of irrecoverable
|
||||
// forkchoice errors
|
||||
const processShutdownCallback: ProcessShutdownCallback = (err) => {
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// MUST import first to apply preset from args and set ssz hasher
|
||||
import "./applyPreset.js";
|
||||
/**
|
||||
* MUST import first!!
|
||||
* - applies preset
|
||||
* - sets ssz hasher
|
||||
* - sets libuv thread pool size
|
||||
*/
|
||||
import "./preInitialization.js";
|
||||
/**
|
||||
* Everything else must be after!!
|
||||
*/
|
||||
import {YargsError} from "./util/index.js";
|
||||
import {getLodestarCli, yarg} from "./cli.js";
|
||||
import "source-map-support/register.js";
|
||||
|
||||
@@ -10,6 +10,7 @@ type GlobalSingleArgs = {
|
||||
paramsFile?: string;
|
||||
preset: string;
|
||||
presetFile?: string;
|
||||
uvThreadpoolSize?: number;
|
||||
};
|
||||
|
||||
export const defaultNetwork: NetworkName = "mainnet";
|
||||
@@ -44,6 +45,12 @@ const globalSingleOptions: CliCommandOptions<GlobalSingleArgs> = {
|
||||
description: "Preset configuration file to override the active preset with custom values",
|
||||
type: "string",
|
||||
},
|
||||
|
||||
uvThreadpoolSize: {
|
||||
hidden: true,
|
||||
description: "Set the number of worker threads libuv should create",
|
||||
type: "number",
|
||||
},
|
||||
};
|
||||
|
||||
export const rcConfigOption: [string, string, (configPath: string) => Record<string, unknown>] = [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// MUST import this file first before anything and not import any Lodestar code.
|
||||
import os from "node:os";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {hasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/as-sha256.js";
|
||||
@@ -29,6 +30,7 @@ import {readFile} from "./util/file.js";
|
||||
const network = valueOfArg("network");
|
||||
const preset = valueOfArg("preset");
|
||||
const presetFile = valueOfArg("presetFile");
|
||||
const uvThreadpoolSize = valueOfArg("uvThreadpoolSize");
|
||||
|
||||
// Apply preset flag if present
|
||||
if (preset) {
|
||||
@@ -61,6 +63,44 @@ else if (process.argv[2] === "dev") {
|
||||
setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the libuv thread pool size for worker threads. This is a critical
|
||||
* component for effective node operations. Setting the environment variable
|
||||
* must happen almost at the beginning of startup, BEFORE the worker pool is
|
||||
* created by libuv.
|
||||
*
|
||||
* The trigger for creation of the libuv worker pool is scheduling async work
|
||||
* that will queue for a worker. An example of things that can trigger that
|
||||
* condition are async reading files from the OS. Some network operations and
|
||||
* any native modules that utilize async work (like @chainsafe/blst-ts).
|
||||
*
|
||||
* Setting this value higher than the number of logical cores will not be a benefit
|
||||
* because the kernel will need to do context switching to parallelize the work
|
||||
* on a number of cores that is less than the number of requested threads.
|
||||
*
|
||||
* Setting this number lower than then number of cores will reduce the amount of
|
||||
* bls work that can be concurrently done. Something like 70% of the work the
|
||||
* cpu does to keep up with the chain is blst validation.
|
||||
*
|
||||
* There is a considerable amount of idle process time on both the main thread
|
||||
* and network thread and setting this value to overlap that work will allow the
|
||||
* kernel to utilize the idle time for additional bls verification.
|
||||
*
|
||||
* Empirical testing has shown that sizing the worker pool to be as large as
|
||||
* the number of logical cores is optimal but this may change in the future.
|
||||
*/
|
||||
if (uvThreadpoolSize) {
|
||||
process.env.UV_THREADPOOL_SIZE = uvThreadpoolSize;
|
||||
} else if (process.env.UV_THREADPOOL_SIZE) {
|
||||
/* no-op let user-set value carry through */
|
||||
} else {
|
||||
process.env.UV_THREADPOOL_SIZE = os.availableParallelism().toString();
|
||||
}
|
||||
|
||||
if (isNaN(parseInt(`${process.env.UV_THREADPOOL_SIZE}`))) {
|
||||
throw new Error(`UV_THREADPOOL_SIZE=${process.env.UV_THREADPOOL_SIZE}, but must be set to a number`);
|
||||
}
|
||||
|
||||
if (presetFile) {
|
||||
// Override the active preset with custom values from file
|
||||
// Do not modify the preset to use as a base by passing null
|
||||
@@ -1,5 +1,5 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/blst";
|
||||
import {CoordType} from "@chainsafe/bls/types";
|
||||
import {fromHexString} from "@chainsafe/ssz";
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
"blockchain"
|
||||
],
|
||||
"dependencies": {
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/blst": "^1.0.0",
|
||||
"@chainsafe/bls-keygen": "^0.4.0",
|
||||
"@lodestar/api": "^1.18.0",
|
||||
"@lodestar/config": "^1.18.0",
|
||||
|
||||
@@ -50,6 +50,12 @@ lodestar lightclient \
|
||||
|
||||
For this example we will assume there is a running beacon node at `https://beacon-node.your-domain.com`
|
||||
|
||||
If you are running light-client on a server/node environment there is a faster version of bls that can help with performance. It is a peerDependency and needs to be installed separately by the consumer of this package. This was done so that for browser situations there is not a hard requirement for node-only code that will cause bundling errors. On startup, if running in a node environment, and `@chainsafe/blst` is installed the LightClient will automatically use the faster bls bindings.
|
||||
|
||||
```sh
|
||||
npm i -S @chainsafe/blst
|
||||
```
|
||||
|
||||
```ts
|
||||
import {getClient} from "@lodestar/api";
|
||||
import {createChainForkConfig} from "@lodestar/config";
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"check-readme": "typescript-docs-verifier"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/persistent-merkle-tree": "^0.7.1",
|
||||
"@chainsafe/ssz": "^0.15.1",
|
||||
"@lodestar/api": "^1.18.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// MUST import first to apply preset from args and set ssz hasher
|
||||
import "./applyPreset.js";
|
||||
import "./preInitialization.js";
|
||||
import {YargsError} from "../utils/errors.js";
|
||||
import {getLodestarProverCli, yarg} from "./cli.js";
|
||||
import "source-map-support/register.js";
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
"types": "lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@chainsafe/as-sha256": "^0.4.1",
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/blst": "^0.2.10",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/blst": "^1.0.0",
|
||||
"@chainsafe/persistent-merkle-tree": "^0.7.1",
|
||||
"@chainsafe/persistent-ts": "^0.19.1",
|
||||
"@chainsafe/ssz": "^0.15.1",
|
||||
|
||||
@@ -174,7 +174,7 @@ describe("CachedBeaconState", () => {
|
||||
// confirm loadCachedBeaconState() result
|
||||
for (let i = 0; i < newCachedState.validators.length; i++) {
|
||||
expect(newCachedState.epochCtx.pubkey2index.get(newCachedState.validators.get(i).pubkey)).toBe(i);
|
||||
expect(newCachedState.epochCtx.index2pubkey[i].toBytes()).toEqual(pubkeys[i]);
|
||||
expect(Uint8Array.from(newCachedState.epochCtx.index2pubkey[i].toBytes())).toEqual(pubkeys[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import {describe, it, expect} from "vitest";
|
||||
import * as blst from "@chainsafe/blst";
|
||||
import {G2_POINT_AT_INFINITY} from "../../src/index.js";
|
||||
|
||||
describe("constants", () => {
|
||||
it("G2_POINT_AT_INFINITY", () => {
|
||||
const p2 = blst.Signature.fromBytes(G2_POINT_AT_INFINITY);
|
||||
expect(p2.value.is_inf()).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -57,7 +57,7 @@
|
||||
"blockchain"
|
||||
],
|
||||
"dependencies": {
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/bls-keystore": "^3.0.1",
|
||||
"@lodestar/params": "^1.18.0",
|
||||
"@lodestar/utils": "^1.18.0",
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"blockchain"
|
||||
],
|
||||
"dependencies": {
|
||||
"@chainsafe/bls": "7.1.3",
|
||||
"@chainsafe/bls": "^8.1.0",
|
||||
"@chainsafe/ssz": "^0.15.1",
|
||||
"@lodestar/api": "^1.18.0",
|
||||
"@lodestar/config": "^1.18.0",
|
||||
|
||||
311
yarn.lock
311
yarn.lock
@@ -293,22 +293,22 @@
|
||||
ethereum-cryptography "^2.0.0"
|
||||
uuid "^9.0.0"
|
||||
|
||||
"@chainsafe/bls@7.1.3":
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@chainsafe/bls/-/bls-7.1.3.tgz#8d488357b187a511cfb94c96eddc7aa9f62644a9"
|
||||
integrity sha512-d21eYdWxDSb63n7nB+viD+3U4yJW8huiKRibJyh8X7btPLoXkvtmDf7geYyHVbKfLDgbuHkc+b48pfPQkUTLxA==
|
||||
"@chainsafe/bls@^8.1.0":
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@chainsafe/bls/-/bls-8.1.0.tgz#d0680ce1e8c10461f7c4c1b7be228a968d77efcb"
|
||||
integrity sha512-C4a1gUpFHYzJG7aaik4w+7QTeJ4pGCDTZ28YUwAWOFaWgAJSK+769ib6CNBu5Txb3PpvcC5GuhICQaDopIgEHg==
|
||||
dependencies:
|
||||
"@chainsafe/bls-keygen" "^0.4.0"
|
||||
bls-eth-wasm "^0.4.8"
|
||||
bls-eth-wasm "^1.1.1"
|
||||
|
||||
"@chainsafe/blst@^0.2.10":
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.2.10.tgz#77802e5b1ff2d98ec1d25dcd5f7d27b89d376a40"
|
||||
integrity sha512-ofecTL5fWsNwnpS2oUh56dDXJRmCEcDKNNBFDb2ux+WtvdjrdSq6B+L/eNlg+sVBzXbzrCw1jq8Y8+cYiHg32w==
|
||||
"@chainsafe/blst@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-1.0.0.tgz#0939f5b38389ca8ae00fcc6b6555063113f611a7"
|
||||
integrity sha512-WQDxFvcG+glmusXnWQ3W4g2tvHuTQEK0/cIZz37TskZJqOqAtOogZsK3cD3j+OoxbdCRT6l08QUCOtPMOLe/zA==
|
||||
dependencies:
|
||||
"@types/tar" "^6.1.4"
|
||||
node-fetch "^2.6.1"
|
||||
node-gyp "^8.4.0"
|
||||
node-addon-api "^6.1.0"
|
||||
node-gyp "^10.0.1"
|
||||
ts-node "^10.9.2"
|
||||
|
||||
"@chainsafe/discv5@^9.0.0":
|
||||
version "9.0.0"
|
||||
@@ -1267,7 +1267,7 @@
|
||||
rfdc "^1.3.0"
|
||||
yaml "^2.2.2"
|
||||
|
||||
"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3":
|
||||
"@gar/promisify@^1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
@@ -2012,13 +2012,16 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@npmcli/fs@^1.0.0":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz"
|
||||
integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==
|
||||
"@npmcli/agent@^2.0.0":
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5"
|
||||
integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==
|
||||
dependencies:
|
||||
"@gar/promisify" "^1.0.1"
|
||||
semver "^7.3.5"
|
||||
agent-base "^7.1.0"
|
||||
http-proxy-agent "^7.0.0"
|
||||
https-proxy-agent "^7.0.1"
|
||||
lru-cache "^10.0.1"
|
||||
socks-proxy-agent "^8.0.3"
|
||||
|
||||
"@npmcli/fs@^2.1.0":
|
||||
version "2.1.0"
|
||||
@@ -2057,14 +2060,6 @@
|
||||
npm-bundled "^3.0.0"
|
||||
npm-normalize-package-bin "^3.0.0"
|
||||
|
||||
"@npmcli/move-file@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674"
|
||||
integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==
|
||||
dependencies:
|
||||
mkdirp "^1.0.4"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
"@npmcli/move-file@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.0.tgz#417f585016081a0184cef3e38902cd917a9bbd02"
|
||||
@@ -2793,11 +2788,6 @@
|
||||
dependencies:
|
||||
defer-to-connect "^2.0.1"
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@tootallnate/once@2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||
@@ -3487,11 +3477,16 @@ JSONStream@^1.3.5:
|
||||
jsonparse "^1.2.0"
|
||||
through ">=2.2.7 <3"
|
||||
|
||||
abbrev@1, abbrev@^1.0.0:
|
||||
abbrev@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
abbrev@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
|
||||
integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz"
|
||||
@@ -3583,7 +3578,14 @@ agent-base@^7.0.2, agent-base@^7.1.0:
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
|
||||
agentkeepalive@^4.1.3, agentkeepalive@^4.2.1:
|
||||
agent-base@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
|
||||
integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
|
||||
agentkeepalive@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717"
|
||||
integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==
|
||||
@@ -4174,10 +4176,10 @@ bl@^5.0.0:
|
||||
inherits "^2.0.4"
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
bls-eth-wasm@^0.4.8:
|
||||
version "0.4.8"
|
||||
resolved "https://registry.npmjs.org/bls-eth-wasm/-/bls-eth-wasm-0.4.8.tgz"
|
||||
integrity sha512-ye7+G6KFLb3i9xSrLASAoYqOUK5WLB6XA5DD8Sh0UQpZ3T999ylsYbFdoOJpmvTDuBuMi23Vy8Jm0pn/GF01CA==
|
||||
bls-eth-wasm@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/bls-eth-wasm/-/bls-eth-wasm-1.2.1.tgz#85f165c17d8f16000f46695b56f72bf6af386825"
|
||||
integrity sha512-hl4oBzZQmPGNb9Wt5GI+oEuHM6twGc5HzXCzNZMVLMMg+dltsOuvuioRyLolpDFbncC0BJbGPzP1ZTysUGkksw==
|
||||
|
||||
bluebird@~3.4.1:
|
||||
version "3.4.7"
|
||||
@@ -4426,30 +4428,6 @@ cac@^6.7.14:
|
||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||
|
||||
cacache@^15.2.0:
|
||||
version "15.3.0"
|
||||
resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb"
|
||||
integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==
|
||||
dependencies:
|
||||
"@npmcli/fs" "^1.0.0"
|
||||
"@npmcli/move-file" "^1.0.1"
|
||||
chownr "^2.0.0"
|
||||
fs-minipass "^2.0.0"
|
||||
glob "^7.1.4"
|
||||
infer-owner "^1.0.4"
|
||||
lru-cache "^6.0.0"
|
||||
minipass "^3.1.1"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.2"
|
||||
mkdirp "^1.0.3"
|
||||
p-map "^4.0.0"
|
||||
promise-inflight "^1.0.1"
|
||||
rimraf "^3.0.2"
|
||||
ssri "^8.0.1"
|
||||
tar "^6.0.2"
|
||||
unique-filename "^1.1.1"
|
||||
|
||||
cacache@^16.1.0:
|
||||
version "16.1.1"
|
||||
resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.1.tgz#4e79fb91d3efffe0630d5ad32db55cc1b870669c"
|
||||
@@ -4493,6 +4471,24 @@ cacache@^17.0.0:
|
||||
tar "^6.1.11"
|
||||
unique-filename "^3.0.0"
|
||||
|
||||
cacache@^18.0.0:
|
||||
version "18.0.2"
|
||||
resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.2.tgz#fd527ea0f03a603be5c0da5805635f8eef00c60c"
|
||||
integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==
|
||||
dependencies:
|
||||
"@npmcli/fs" "^3.1.0"
|
||||
fs-minipass "^3.0.0"
|
||||
glob "^10.2.2"
|
||||
lru-cache "^10.0.1"
|
||||
minipass "^7.0.3"
|
||||
minipass-collect "^2.0.1"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.4"
|
||||
p-map "^4.0.0"
|
||||
ssri "^10.0.0"
|
||||
tar "^6.1.11"
|
||||
unique-filename "^3.0.0"
|
||||
|
||||
cacheable-lookup@^5.0.3:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
|
||||
@@ -5648,7 +5644,7 @@ enabled@2.0.x:
|
||||
resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz"
|
||||
integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
|
||||
|
||||
encoding@^0.1.12, encoding@^0.1.13:
|
||||
encoding@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
|
||||
@@ -6930,6 +6926,17 @@ glob@^10.2.2:
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
path-scurry "^1.10.1"
|
||||
|
||||
glob@^10.3.10:
|
||||
version "10.3.12"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b"
|
||||
integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==
|
||||
dependencies:
|
||||
foreground-child "^3.1.0"
|
||||
jackspeak "^2.3.6"
|
||||
minimatch "^9.0.1"
|
||||
minipass "^7.0.4"
|
||||
path-scurry "^1.10.2"
|
||||
|
||||
glob@^7.1.3, glob@^7.1.4:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
@@ -7222,15 +7229,6 @@ http-errors@2.0.0:
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
http-proxy-agent@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
|
||||
integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
|
||||
dependencies:
|
||||
"@tootallnate/once" "1"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43"
|
||||
@@ -7294,18 +7292,18 @@ https-proxy-agent@^5.0.0:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
https-proxy-agent@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b"
|
||||
integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==
|
||||
https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168"
|
||||
integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==
|
||||
dependencies:
|
||||
agent-base "^7.0.2"
|
||||
debug "4"
|
||||
|
||||
https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168"
|
||||
integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==
|
||||
https-proxy-agent@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b"
|
||||
integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==
|
||||
dependencies:
|
||||
agent-base "^7.0.2"
|
||||
debug "4"
|
||||
@@ -8069,7 +8067,7 @@ jackspeak@^2.0.3:
|
||||
optionalDependencies:
|
||||
"@pkgjs/parseargs" "^0.11.0"
|
||||
|
||||
jackspeak@^2.3.5:
|
||||
jackspeak@^2.3.5, jackspeak@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
|
||||
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
|
||||
@@ -8713,7 +8711,7 @@ lowercase-keys@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2"
|
||||
integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==
|
||||
|
||||
lru-cache@^10.1.0, "lru-cache@^9.1.1 || ^10.0.0":
|
||||
lru-cache@^10.0.1, lru-cache@^10.1.0, lru-cache@^10.2.0, "lru-cache@^9.1.1 || ^10.0.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
|
||||
integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
|
||||
@@ -8816,27 +8814,22 @@ make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1, make-fetch-happen@^11.1.1:
|
||||
socks-proxy-agent "^7.0.0"
|
||||
ssri "^10.0.0"
|
||||
|
||||
make-fetch-happen@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz"
|
||||
integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==
|
||||
make-fetch-happen@^13.0.0:
|
||||
version "13.0.0"
|
||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0"
|
||||
integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==
|
||||
dependencies:
|
||||
agentkeepalive "^4.1.3"
|
||||
cacache "^15.2.0"
|
||||
http-cache-semantics "^4.1.0"
|
||||
http-proxy-agent "^4.0.1"
|
||||
https-proxy-agent "^5.0.0"
|
||||
"@npmcli/agent" "^2.0.0"
|
||||
cacache "^18.0.0"
|
||||
http-cache-semantics "^4.1.1"
|
||||
is-lambda "^1.0.1"
|
||||
lru-cache "^6.0.0"
|
||||
minipass "^3.1.3"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-fetch "^1.3.2"
|
||||
minipass "^7.0.2"
|
||||
minipass-fetch "^3.0.0"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.4"
|
||||
negotiator "^0.6.2"
|
||||
negotiator "^0.6.3"
|
||||
promise-retry "^2.0.1"
|
||||
socks-proxy-agent "^6.0.0"
|
||||
ssri "^8.0.0"
|
||||
ssri "^10.0.0"
|
||||
|
||||
map-obj@^1.0.0:
|
||||
version "1.0.1"
|
||||
@@ -9075,16 +9068,12 @@ minipass-collect@^1.0.2:
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-fetch@^1.3.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6"
|
||||
integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==
|
||||
minipass-collect@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863"
|
||||
integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==
|
||||
dependencies:
|
||||
minipass "^3.1.0"
|
||||
minipass-sized "^1.0.3"
|
||||
minizlib "^2.0.0"
|
||||
optionalDependencies:
|
||||
encoding "^0.1.12"
|
||||
minipass "^7.0.3"
|
||||
|
||||
minipass-fetch@^2.0.3:
|
||||
version "2.1.0"
|
||||
@@ -9123,7 +9112,7 @@ minipass-json-stream@^1.0.1:
|
||||
jsonparse "^1.3.1"
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4:
|
||||
minipass-pipeline@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
|
||||
integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
|
||||
@@ -9137,7 +9126,7 @@ minipass-sized@^1.0.3:
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6:
|
||||
minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
|
||||
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
|
||||
@@ -9154,12 +9143,12 @@ minipass@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
|
||||
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
|
||||
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
|
||||
|
||||
minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2:
|
||||
minizlib@^2.1.1, minizlib@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
|
||||
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
|
||||
@@ -9357,7 +9346,7 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
negotiator@^0.6.2, negotiator@^0.6.3:
|
||||
negotiator@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
@@ -9387,6 +9376,11 @@ node-addon-api@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762"
|
||||
integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==
|
||||
|
||||
node-addon-api@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
|
||||
integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
@@ -9425,21 +9419,21 @@ node-gyp-build@^4.3.0:
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
|
||||
integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==
|
||||
|
||||
node-gyp@^8.4.0:
|
||||
version "8.4.1"
|
||||
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz"
|
||||
integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==
|
||||
node-gyp@^10.0.1:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.1.0.tgz#75e6f223f2acb4026866c26a2ead6aab75a8ca7e"
|
||||
integrity sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
glob "^7.1.4"
|
||||
exponential-backoff "^3.1.1"
|
||||
glob "^10.3.10"
|
||||
graceful-fs "^4.2.6"
|
||||
make-fetch-happen "^9.1.0"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^6.0.0"
|
||||
rimraf "^3.0.2"
|
||||
make-fetch-happen "^13.0.0"
|
||||
nopt "^7.0.0"
|
||||
proc-log "^3.0.0"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.2"
|
||||
which "^2.0.2"
|
||||
which "^4.0.0"
|
||||
|
||||
node-gyp@^9.0.0, node-gyp@^9.4.0:
|
||||
version "9.4.1"
|
||||
@@ -9525,13 +9519,6 @@ node-stdlib-browser@^1.2.0:
|
||||
util "^0.12.4"
|
||||
vm-browserify "^1.0.1"
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d"
|
||||
@@ -9539,6 +9526,13 @@ nopt@^6.0.0:
|
||||
dependencies:
|
||||
abbrev "^1.0.0"
|
||||
|
||||
nopt@^7.0.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7"
|
||||
integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==
|
||||
dependencies:
|
||||
abbrev "^2.0.0"
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
@@ -10282,6 +10276,14 @@ path-scurry@^1.10.1, path-scurry@^1.6.1:
|
||||
lru-cache "^9.1.1 || ^10.0.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-scurry@^1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7"
|
||||
integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==
|
||||
dependencies:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-type@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
||||
@@ -11436,15 +11438,6 @@ snappyjs@^0.7.0:
|
||||
resolved "https://registry.yarnpkg.com/snappyjs/-/snappyjs-0.7.0.tgz#6096eac06382700ae7fdefa579dea5e2aa20f51c"
|
||||
integrity sha512-u5iEEXkMe2EInQio6Wv9LWHOQYRDbD2O9hzS27GpT/lwfIQhTCnHCTqedqHIHe9ZcvQo+9au6vngQayipz1NYw==
|
||||
|
||||
socks-proxy-agent@^6.0.0:
|
||||
version "6.1.1"
|
||||
resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz"
|
||||
integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==
|
||||
dependencies:
|
||||
agent-base "^6.0.2"
|
||||
debug "^4.3.1"
|
||||
socks "^2.6.1"
|
||||
|
||||
socks-proxy-agent@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6"
|
||||
@@ -11463,7 +11456,16 @@ socks-proxy-agent@^8.0.2:
|
||||
debug "^4.3.4"
|
||||
socks "^2.7.1"
|
||||
|
||||
socks@^2.6.1, socks@^2.6.2, socks@^2.7.1:
|
||||
socks-proxy-agent@^8.0.3:
|
||||
version "8.0.3"
|
||||
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz#6b2da3d77364fde6292e810b496cb70440b9b89d"
|
||||
integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==
|
||||
dependencies:
|
||||
agent-base "^7.1.1"
|
||||
debug "^4.3.4"
|
||||
socks "^2.7.1"
|
||||
|
||||
socks@^2.6.2, socks@^2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
|
||||
integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
|
||||
@@ -11594,13 +11596,6 @@ ssri@^10.0.0, ssri@^10.0.1:
|
||||
dependencies:
|
||||
minipass "^4.0.0"
|
||||
|
||||
ssri@^8.0.0, ssri@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
|
||||
integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
|
||||
dependencies:
|
||||
minipass "^3.1.1"
|
||||
|
||||
ssri@^9.0.0, ssri@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057"
|
||||
@@ -11702,16 +11697,7 @@ strict-event-emitter-types@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz"
|
||||
integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -12002,7 +11988,7 @@ tar@6.1.11:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tar@^6.0.2, tar@^6.1.11, tar@^6.1.13, tar@^6.1.2:
|
||||
tar@^6.1.11, tar@^6.1.13, tar@^6.1.2:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
|
||||
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
|
||||
@@ -13315,16 +13301,7 @@ workerpool@6.2.1:
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
|
||||
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
|
||||
Reference in New Issue
Block a user