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 commit f71acd7d6d.

* Revert "fix: light-client e2e test"

This reverts commit 23c11f0a7d.

* Revert "fix: light-client unit tests"

This reverts commit fa7893ed8e.

* Revert "test: fix browser based tests"

This reverts commit 98d04ab172.

* 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:
Matthew Keil
2024-04-24 09:09:41 -04:00
committed by GitHub
parent 2649a87aab
commit 97d9aa8b0c
34 changed files with 421 additions and 516 deletions

View File

@@ -163,6 +163,7 @@ orchestrator
osx
overriden
params
peerDependency
pid
plaintext
pre

View File

@@ -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",

View File

@@ -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",

View File

@@ -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";

View File

@@ -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]))),
},
],
};

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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};

View File

@@ -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;
}

View File

@@ -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,
};
}

View File

@@ -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) {

View File

@@ -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 */

View File

@@ -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;
}

View 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;
}
}

View File

@@ -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;
}

View File

@@ -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 () {

View File

@@ -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", () => {

View File

@@ -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",

View File

@@ -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) => {

View File

@@ -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";

View File

@@ -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>] = [

View File

@@ -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

View File

@@ -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";
/**

View File

@@ -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",

View File

@@ -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";

View File

@@ -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",

View File

@@ -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";

View File

@@ -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",

View File

@@ -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]);
}
});
}

View File

@@ -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);
});
});

View File

@@ -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",

View File

@@ -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
View File

@@ -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==