diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 64937957191c..72af86de75bd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,6 +3,8 @@ { "name": "Node.js & TypeScript", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + // Upgrade the container to Node 22 + // https://github.com/ChainSafe/lodestar/issues/6742 "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye", "features": { "ghcr.io/devcontainers/features/python:1": {} diff --git a/.eslintrc.js b/.eslintrc.js index fdfae1a1a00d..cf6c3b95726c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -194,7 +194,14 @@ module.exports = { }, overrides: [ { - files: ["**/*.config.js", "**/*.config.mjs", "**/*.config.cjs", "**/*.config.ts"], + files: [ + "**/*.config.js", + "**/*.config.mjs", + "**/*.config.cjs", + "**/*.config.ts", + "scripts/vitest/**/*.ts", + "scripts/vite/**/*.ts", + ], rules: { "@typescript-eslint/naming-convention": "off", // Allow require in CJS modules diff --git a/.github/actions/setup-and-build/action.yml b/.github/actions/setup-and-build/action.yml index f2575ea04565..ccb170d69fa3 100644 --- a/.github/actions/setup-and-build/action.yml +++ b/.github/actions/setup-and-build/action.yml @@ -30,7 +30,7 @@ runs: lib/ packages/*/lib packages/*/.git-data.json - key: ${{ runner.os }}-node-${{ inputs.node }}-${{ github.sha }} + key: ${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node }}-${{ github.sha }} - name: Install & build if: steps.cache-build-restore.outputs.cache-hit != 'true' @@ -55,4 +55,4 @@ runs: lib/ packages/*/lib packages/*/.git-data.json - key: ${{ runner.os }}-node-${{ inputs.node }}-${{ github.sha }} + key: ${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node }}-${{ github.sha }} diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index efb9e0231e20..e515bef7f92a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 check-latest: true cache: yarn - name: Node.js version diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml new file mode 100644 index 000000000000..469b0803c378 --- /dev/null +++ b/.github/workflows/binaries.yml @@ -0,0 +1,71 @@ +name: Build binaries + +on: + workflow_dispatch: + inputs: + version: + required: true + type: string + workflow_call: + inputs: + version: + required: true + type: string + +jobs: + binaries: + name: Build lodestar binaries + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + platform: linux + arch: amd64 + - os: lodestar-arm64-runner + platform: linux + arch: arm64 + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v4 + - name: Install arm64 specifics + if: matrix.arch == 'arm64' + run: |- + # Install missing yarn + # See https://github.com/github-early-access/arm-runners-beta/issues/5 + curl -fsSL --create-dirs -o $HOME/bin/yarn \ + https://github.com/yarnpkg/yarn/releases/download/v1.22.22/yarn-1.22.22.js + chmod +x $HOME/bin/yarn + echo "$HOME/bin" >> $GITHUB_PATH + # Install missing build-essential + sudo apt-get update + sudo apt-get install -y build-essential python3 + - uses: "./.github/actions/setup-and-build" + with: + node: 22 + - run: | + mkdir -p dist + yarn global add caxa@3.0.1 + npx caxa -m "Unpacking Lodestar binary, please wait..." -e "dashboards/**" -e "docs/**" -D -p "yarn install --frozen-lockfile --production" --input . --output "lodestar" -- "{{caxa}}/node_modules/.bin/node" "--max-old-space-size=8192" "{{caxa}}/node_modules/.bin/lodestar" + tar -czf "dist/lodestar-${{ inputs.version }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz" "lodestar" + - name: Upload binaries + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.os }} + path: dist/ + if-no-files-found: error + - name: Sanity check binary + uses: actions/github-script@v7 + with: + script: | + exec.exec('./lodestar dev'); + await new Promise(resolve => setTimeout(resolve, 30000)); + const resp = await fetch('http://127.0.0.1:9596/eth/v1/node/version').catch(err => { + core.setFailed(`Error accessing the API ${err}`); + process.exit(1); + }); + if (resp.status !== 200) { + core.setFailed(`Failed to access API: ${resp.status}`); + process.exit(1); + } + process.exit(0); diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index 9ad566c417e2..021e5019760d 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: yarn - name: Node.js version id: node diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 61a9f0eba3d1..b8f4e7b95eb0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 check-latest: true cache: yarn diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index e38abd9e68dc..da045764dd41 100644 --- a/.github/workflows/publish-dev.yml +++ b/.github/workflows/publish-dev.yml @@ -20,7 +20,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 registry-url: "https://registry.npmjs.org" check-latest: true cache: yarn diff --git a/.github/workflows/publish-rc.yml b/.github/workflows/publish-rc.yml index fde36df5f1f1..35831822bcdc 100644 --- a/.github/workflows/publish-rc.yml +++ b/.github/workflows/publish-rc.yml @@ -42,10 +42,17 @@ jobs: tag: ${{ steps.get_tag.outputs.tag }} prev_tag: ${{ steps.get_prev_tag.outputs.prev_tag }} + binaries: + name: Build lodestar binaries + uses: ./.github/workflows/binaries.yml + needs: tag + with: + version: ${{ needs.tag.outputs.tag }} + npm: name: Publish to NPM & Github runs-on: buildjet-4vcpu-ubuntu-2204 - needs: tag + needs: [tag, binaries] if: needs.tag.outputs.is_rc == 'true' steps: - uses: actions/checkout@v4 @@ -54,17 +61,25 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md + - name: Get binaries + uses: actions/download-artifact@v4 + with: + path: dist/ + merge-multiple: true + - name: Create Release id: create_release uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: + files: dist/* + fail_on_unmatched_files: true tag_name: ${{ needs.tag.outputs.tag }} body_path: "CHANGELOG.md" name: Release ${{ needs.tag.outputs.tag }} diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index 26e9c094881c..741c060e4d20 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -48,10 +48,17 @@ jobs: tag: ${{ steps.get_tag.outputs.tag }} prev_tag: ${{ steps.get_prev_tag.outputs.prev_tag }} + binaries: + name: Build lodestar binaries + uses: ./.github/workflows/binaries.yml + needs: tag + with: + version: ${{ needs.tag.outputs.tag }} + npm: name: Publish to NPM & Github runs-on: buildjet-4vcpu-ubuntu-2204 - needs: tag + needs: [tag, binaries] if: needs.tag.outputs.is_stable == 'true' steps: - uses: actions/checkout@v4 @@ -60,17 +67,25 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md + - name: Get binaries + uses: actions/download-artifact@v4 + with: + path: dist/ + merge-multiple: true + - name: Create Release id: create_release uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: + files: dist/* + fail_on_unmatched_files: true tag_name: ${{ needs.tag.outputs.tag }} body_path: "CHANGELOG.md" name: Release ${{ needs.tag.outputs.tag }} diff --git a/.github/workflows/test-sim-merge.yml b/.github/workflows/test-sim-merge.yml index bd957c596a41..ad79bc2c0035 100644 --- a/.github/workflows/test-sim-merge.yml +++ b/.github/workflows/test-sim-merge.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 check-latest: true cache: yarn - name: Node.js version diff --git a/.github/workflows/test-sim.yml b/.github/workflows/test-sim.yml index 0a00777bfeca..ff28149537d3 100644 --- a/.github/workflows/test-sim.yml +++ b/.github/workflows/test-sim.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 sim-test-multifork: name: Multifork sim test @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Load env variables uses: ./.github/actions/dotenv - name: Download required docker images before running tests @@ -71,7 +71,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Load env variables uses: ./.github/actions/dotenv - name: Download required docker images before running tests @@ -100,7 +100,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Load env variables uses: ./.github/actions/dotenv - name: Download required docker images before running tests @@ -129,7 +129,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Load env variables uses: ./.github/actions/dotenv - name: Download required docker images before running tests @@ -158,7 +158,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 20 + node: 22 - name: Load env variables uses: ./.github/actions/dotenv - name: Download required docker images before running tests diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 046cbe1f3cce..f55eb661629f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -74,7 +74,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: - uses: actions/checkout@v4 @@ -95,7 +95,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -134,7 +134,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -171,7 +171,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -195,7 +195,7 @@ jobs: strategy: fail-fast: false matrix: - node: [20] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" diff --git a/.gitignore b/.gitignore index 4f4289359a4c..a6d12b02445b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .__testdb* node_modules/ lib +dist .nyc_output/ coverage/** .DS_Store @@ -21,10 +22,13 @@ validators **/coverage **/node_modules **/lib +**/dist **/.nyc_output .tmp -.vscode .npmrc +.vscode/launch.json +.vscode/settings.json +.vscode/tasks.json # Tests artifacts packages/*/spec-tests* diff --git a/.vscode/README.md b/.vscode/README.md new file mode 100644 index 000000000000..982806622c7d --- /dev/null +++ b/.vscode/README.md @@ -0,0 +1,3 @@ +Copy `launch.template.json` as `launch.json` and adapt to your needs. + +See [Debugging](../docs/pages/tools/debugging.md) for more details. diff --git a/.vscode/launch.template.json b/.vscode/launch.template.json new file mode 100644 index 000000000000..b617723a0066 --- /dev/null +++ b/.vscode/launch.template.json @@ -0,0 +1,79 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "name": "Attach", + "port": 9229, + "request": "attach", + "skipFiles": [ + "/**" + ] + }, + { + "type": "node", + "request": "launch", + "name": "Beacon", + "skipFiles": [ + "/**" + ], + "smartStep": true, + "program": "${workspaceFolder}/packages/cli/bin/lodestar.js", + "args": [ + "beacon" + ], + "console": "integratedTerminal" + }, + { + "type": "node", + "request": "launch", + "name": "Dev", + "skipFiles": [ + "/**" + ], + "smartStep": true, + "program": "${workspaceFolder}/packages/cli/bin/lodestar.js", + "args": [ + "dev" + ], + "console": "integratedTerminal" + }, + { + "name": "Test Current File", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/node_modules/.bin/vitest", + "args": [ + "--run", + "${file}", + "-t", + "${input:testName}", + "--pool", + "threads", + "--poolOptions.threads.singleThread" + ], + "cwd": "${workspaceFolder}/${input:packageName}", + "console": "integratedTerminal", + "skipFiles": [ + "/**" + ] + } + ], + "inputs": [ + { + "id": "packageName", + "type": "command", + "command": "extension.commandvariable.transform", + "args": { + "text": "${relativeFileDirname}", + "find": "^(packages/[^/]+).*", + "replace": "$1" + } + }, + { + "id": "testName", + "type": "promptString", + "description": "Enter the test name to run, leave empty to run all" + } + ] +} diff --git a/.wordlist.txt b/.wordlist.txt index d26663186357..64d72550755b 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -41,6 +41,7 @@ Geth Github Gossipsub Grafana +Grandine HTTPS HackMD Homebrew @@ -60,6 +61,8 @@ LTS Lerna MEV MacOS +Metamask +ModuleNotFoundError Monorepo NPM NVM @@ -98,6 +101,7 @@ blockRoot blockchain bootnode bootnodes +bundlers chainConfig chainsafe chiado @@ -122,12 +126,14 @@ devcontainer devnet devnets devtools +distutils eg enodes enum env envs ephemery +ethers flamegraph flamegraphs getNetworkIdentity @@ -192,11 +198,14 @@ testnets todo typesafe udp +unpkg util utils validator validators +vite vitest +webpack wip xcode yaml diff --git a/Dockerfile b/Dockerfile index a9e597c2fb9f..fdab1140af47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ # --platform=$BUILDPLATFORM is used build javascript source with host arch # Otherwise TS builds on emulated archs and can be extremely slow (+1h) -FROM --platform=${BUILDPLATFORM:-amd64} node:20-alpine as build_src +FROM --platform=${BUILDPLATFORM:-amd64} node:22-alpine as build_src ARG COMMIT WORKDIR /usr/app -RUN apk update && apk add --no-cache g++ make python3 && rm -rf /var/cache/apk/* +RUN apk update && apk add --no-cache g++ make python3 py3-setuptools && rm -rf /var/cache/apk/* COPY . . @@ -21,9 +21,9 @@ RUN cd packages/cli && GIT_COMMIT=${COMMIT} yarn write-git-data # Copy built src + node_modules to build native packages for archs different than host. # Note: This step is redundant for the host arch -FROM node:20-alpine as build_deps +FROM node:22-alpine as build_deps WORKDIR /usr/app -RUN apk update && apk add --no-cache g++ make python3 && rm -rf /var/cache/apk/* +RUN apk update && apk add --no-cache g++ make python3 py3-setuptools && rm -rf /var/cache/apk/* COPY --from=build_src /usr/app . @@ -35,7 +35,7 @@ RUN cd node_modules/classic-level && yarn rebuild # Copy built src + node_modules to a new layer to prune unnecessary fs # Previous layer weights 7.25GB, while this final 488MB (as of Oct 2020) -FROM node:20-alpine +FROM node:22-alpine WORKDIR /usr/app COPY --from=build_deps /usr/app . diff --git a/README.md b/README.md index 3b157721ee1d..8546a467f404 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/chainsafe/lodestar?label=Github)](https://github.com/ChainSafe/lodestar/releases/latest) [![Docker Image Version (latest by date)](https://img.shields.io/docker/v/chainsafe/lodestar?color=blue&label=Docker&sort=semver)](https://hub.docker.com/r/chainsafe/lodestar) -[![Ethereum Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) [![codecov](https://codecov.io/gh/ChainSafe/lodestar/graph/badge.svg)](https://codecov.io/gh/ChainSafe/lodestar) [![gitpoap badge](https://public-api.gitpoap.io/v1/repo/ChainSafe/lodestar/badge)](https://www.gitpoap.io/gh/ChainSafe/lodestar) diff --git a/RELEASE.md b/RELEASE.md index b38a4f8562f6..91b450baa34a 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -271,7 +271,7 @@ Historical context and reasons against valid alternatives to help future discuss Lodestar used `master` as the single target for feature branches. -![lodestar-release](docs/images/lodestar-releases.png) +![lodestar-release](docs/static/images/lodestar-releases.png) - Main branch = `master` - Features merged to `master` diff --git a/dashboards/lodestar_state_cache_regen.json b/dashboards/lodestar_state_cache_regen.json index bccac0ff2573..be52d414ea3b 100644 --- a/dashboards/lodestar_state_cache_regen.json +++ b/dashboards/lodestar_state_cache_regen.json @@ -1309,7 +1309,48 @@ "mappings": [], "unit": "s" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "count_per_epoch" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "count_per_epoch" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -1356,6 +1397,19 @@ "legendFormat": "sec_from_slot", "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(lodestar_cp_state_cache_state_persist_seconds_from_slot_count[$rate_interval]) * 384", + "hide": false, + "instant": false, + "legendFormat": "count_per_epoch", + "range": true, + "refId": "C" } ], "title": "State persist", diff --git a/docker/docker-compose.local.yml b/docker/docker-compose.local.yml index bd0b225a624d..a14d9a4eafbe 100644 --- a/docker/docker-compose.local.yml +++ b/docker/docker-compose.local.yml @@ -7,28 +7,30 @@ services: build: context: prometheus environment: - # Linux: http://localhost:8008 - # MacOSX: http://host.docker.internal:8008 - BEACON_URL: localhost:8008 - VC_URL: localhost:5064 + BEACON_URL: host.docker.internal:8008 + VC_URL: host.docker.internal:5064 restart: always - network_mode: host volumes: - "prometheus:/prometheus" + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "127.0.0.1:9090:9090" grafana: build: context: .. dockerfile: docker/grafana restart: always - network_mode: host volumes: - "grafana:/var/lib/grafana" - "grafana-dashboards:/dashboards" environment: - # Linux: http://localhost:9090 - # MacOSX: http://host.docker.internal:9090 - PROMETHEUS_URL: http://localhost:9090 + PROMETHEUS_URL: http://host.docker.internal:9090 + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "127.0.0.1:3000:3000" volumes: prometheus: diff --git a/docker/docker-compose.local_dev.yml b/docker/docker-compose.local_dev.yml index 0a3f10cd0695..e25126175abd 100644 --- a/docker/docker-compose.local_dev.yml +++ b/docker/docker-compose.local_dev.yml @@ -12,26 +12,28 @@ services: build: context: prometheus environment: - # Linux: http://localhost:8008 - # MacOSX: http://host.docker.internal:8008 - BEACON_URL: localhost:8008 - VC_URL: localhost:5064 + BEACON_URL: host.docker.internal:8008 + VC_URL: host.docker.internal:5064 restart: always - network_mode: host volumes: - "prometheus:/prometheus" + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "127.0.0.1:9090:9090" grafana: build: grafana_dev restart: always - network_mode: host volumes: - "grafana:/var/lib/grafana" - "grafana-dashboards:/dashboards" environment: - # Linux: http://localhost:9090 - # MacOSX: http://host.docker.internal:9090 - PROMETHEUS_URL: http://localhost:9090 + PROMETHEUS_URL: http://host.docker.internal:9090 + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "127.0.0.1:3000:3000" volumes: prometheus: diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 8c86ac4405ba..0479fe696170 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -8,7 +8,7 @@ import {themes as prismThemes} from "prism-react-renderer"; const config: Config = { title: "Lodestar", tagline: "TypeScript Implementation of Ethereum Consensus", - favicon: "img/favicon.ico", + favicon: "images/favicon.ico", // Set the production url of your site here url: "https://chainsafe.github.io/", @@ -55,7 +55,7 @@ const config: Config = { title: "Lodestar Documentation", logo: { alt: "Lodestar Logo", - src: "img/logo.png", + src: "images/logo.png", }, items: [ { @@ -105,10 +105,8 @@ const config: Config = { minHeadingLevel: 2, maxHeadingLevel: 5, }, - scripts: [ - {src: "https://plausible.io/js/script.js", defer: true, "data-domain": "https://chainsafe.github.io/lodestar/"}, - ], } satisfies Preset.ThemeConfig, + scripts: [{src: "https://plausible.io/js/script.js", defer: true, "data-domain": "chainsafe.github.io/lodestar"}], }; export default config; diff --git a/docs/pages/contribution/testing/index.md b/docs/pages/contribution/testing/index.md index 9de62895323c..fd1f8e47a6e4 100644 --- a/docs/pages/contribution/testing/index.md +++ b/docs/pages/contribution/testing/index.md @@ -2,6 +2,12 @@ Testing is critical to the Lodestar project and there are many types of tests that are run to build a product that is both effective AND efficient. This page will help to break down the different types of tests you will find in the Lodestar repo. +There are few flags you can set through env variables to override behavior of testing and it's output. + +| ENV variable | Effect | Impact | +| ----------------- | ------ | ----------------------------------------------------------------------------------------------------------- | +| TEST_COMPACT_DIFF | All | Will strip down the object difference rendered during test failures. Very useful for large object matching. | + ### Unit Tests This is the most fundamental type of test in most code bases. In all instances mocks, stubs and other forms of isolation are used to test code on a functional, unit level. See the [Unit Tests](./unit-tests.md) page for more information. diff --git a/docs/pages/faqs.md b/docs/pages/faqs.md index 01732c5c11fa..d86f2a37471e 100644 --- a/docs/pages/faqs.md +++ b/docs/pages/faqs.md @@ -4,6 +4,19 @@ This section of the documentation will cover common questions and encounters oft ## Troubleshooting Lodestar +### Running a beacon node + +:::note "Heap memory limit" +Lodestar beacon node requires at least 8GB of heap space. While the `lodestar` script and the official docker image correctly sets the appropriate value, it might be necessary to manually set it for some specific scenario. + +The simplest way to achieve this is via the `NODE_OPTIONS` environment variable or by passing [`--max-old-space-size`](https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-megabytes) directly to the node binary + +```bash +NODE_OPTIONS: --max-old-space-size=8192 +``` + +::: + ### Using Kubernetes :::note "Unknown arguments error" diff --git a/docs/pages/getting-started/installation.md b/docs/pages/getting-started/installation.md index 7630f031dda0..cf53916e054c 100644 --- a/docs/pages/getting-started/installation.md +++ b/docs/pages/getting-started/installation.md @@ -32,7 +32,7 @@ Docker is the recommended setup for Lodestar. Use our [Lodestar Quickstart scrip ### Prerequisites -Make sure to have [Yarn installed](https://classic.yarnpkg.com/en/docs/install). It is also recommended to [install NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) and use the LTS version (currently v20) of [NodeJS](https://nodejs.org/en/). +Make sure to have [Yarn installed](https://classic.yarnpkg.com/en/docs/install). It is also recommended to [install NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) and use the LTS version (currently v22) of [NodeJS](https://nodejs.org/en/). :::info NodeJS versions older than the current LTS are not supported by Lodestar. We recommend running the latest Node LTS. @@ -83,6 +83,16 @@ Lodestar should now be ready for use. See [Command Line Reference](./../reference/cli.md) for further information. +### Known Issues + +**ModuleNotFoundError: No module named 'distutils'** + +If you stump upon this issue while running Yarn, it's because Python 3.12 had removed `distutils` package. That package is required for node build tool. You can install it with following command. + +```bash +pip3 install setuptools --force-reinstall --user +``` + ## Install from NPM [not recommended] :::danger diff --git a/docs/pages/introduction.md b/docs/pages/introduction.md index 12b00dacf0a5..ab864b8a9df8 100644 --- a/docs/pages/introduction.md +++ b/docs/pages/introduction.md @@ -15,12 +15,13 @@ In an effort to promote client diversity there are several beacon-nodes being de - [Lighthouse](https://lighthouse.sigmaprime.io/) - [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) - [Nimbus](https://nimbus.team/) +- [Grandine](https://grandine.io) ## Why Client Diversity? The Ethereum network's robustness is significantly enhanced by its client diversity, whereby multiple, independently-developed clients conforming to a common specification facilitate seamless interaction and function equivalently across nodes. This client variety not only fosters a rich ecosystem but also provides a buffer against network-wide issues stemming from bugs or malicious attacks targeted at particular clients. For instance, during the Shanghai denial-of-service attack in 2016, the diversified client structure enabled the network to withstand the assault, underscoring the resilience afforded by multiple client configurations. -On the consensus layer, client distribution is crucial for maintaining network integrity and finality, ensuring transactions are irreversible once validated. A balanced spread of nodes across various clients helps mitigate risks associated with potential bugs or attacks that could, in extreme cases, derail the consensus process or lead to incorrect chain splits, thereby jeopardizing the network's stability and trust. While the data suggests a dominance of Prysm client on the consensus layer, efforts are ongoing to promote a more even distribution among others like Lighthouse, Teku, and Nimbus. Encouraging the adoption of minority clients, bolstering their documentation, and leveraging real-time client diversity dashboards are among the strategies being employed to enhance client diversity, which in turn fortifies the Ethereum consensus layer against adversities and fosters a healthier decentralized network ecosystem. +On the consensus layer, client distribution is crucial for maintaining network integrity and finality, ensuring transactions are irreversible once validated. A balanced spread of nodes across various clients helps mitigate risks associated with potential bugs or attacks that could, in extreme cases, derail the consensus process or lead to incorrect chain splits, thereby jeopardizing the network's stability and trust. While the data suggests a dominance of Prysm client on the consensus layer, efforts are ongoing to promote a more even distribution among others like Lighthouse, Teku, Nimbus and Grandine. Encouraging the adoption of minority clients, bolstering their documentation, and leveraging real-time client diversity dashboards are among the strategies being employed to enhance client diversity, which in turn fortifies the Ethereum consensus layer against adversities and fosters a healthier decentralized network ecosystem. The non-finality event in May 2023 on the Ethereum network posed a significant challenge. The issue arose from attestations for a fork, which necessitated state replays to validate the attestations, causing a notable strain on system resources. As a result, nodes fell out of sync, which deterred the accurate tracking of the actual head of the chain. This situation was exacerbated by a decline in attestations during specific epochs, further hampering the consensus mechanism. The Lodestar team noticed late attestations several weeks prior to the event and implemented a feature that attempted to address such challenges by not processing untimely attestations, and thus not requiring expensive state replays​. While it was done for slightly different reasons, the result was the same. Lodestar was able to follow the chain correctly and helped to stabilize the network. This example underscored the importance of client diversity and network resilience against potential forks and replay attacks. These are considered realistic threats, especially in the context of system complexity like in Ethereum's consensus mechanism. diff --git a/docs/pages/tools/core-dumps.md b/docs/pages/tools/core-dumps.md index 21f2e6a08f58..519e018e7ca5 100644 --- a/docs/pages/tools/core-dumps.md +++ b/docs/pages/tools/core-dumps.md @@ -30,7 +30,7 @@ $ which llvm-config /opt/homebrew/opt/llvm/bin/llvm-config # if this is not what comes up restart the shell $ npm install -g llnode $ llnode -(lldb) plugin load '/Users/ninja_user/.nvm/versions/node/v20.5.1/lib/node_modules/llnode/llnode.dylib' +(lldb) plugin load '/Users/ninja_user/.nvm/versions/node/v22.1.0/lib/node_modules/llnode/llnode.dylib' (lldb) settings set prompt '(llnode) ' (llnode) ``` @@ -58,7 +58,7 @@ Once you collect the core dump you can load it into `llnode` for debugging. $ llnode -f /path/to/node_debug -c /Users/ninja_user/coredumps/node.coredump (lldb) target create "node_debug" --core "node.coredump" Core file '/Users/ninja_user/coredumps/node.coredump' (x86_64) was loaded. -(lldb) plugin load '/Users/ninja_user/.nvm/versions/node/v20.5.1/lib/node_modules/llnode/llnode.dylib' +(lldb) plugin load '/Users/ninja_user/.nvm/versions/node/v22.1.0/lib/node_modules/llnode/llnode.dylib' (lldb) settings set prompt '(llnode) ' (llnode) ``` diff --git a/docs/pages/tools/debugging.md b/docs/pages/tools/debugging.md index e69de29bb2d1..0775a3feb0b2 100644 --- a/docs/pages/tools/debugging.md +++ b/docs/pages/tools/debugging.md @@ -0,0 +1,24 @@ +# Debugging + +This page describes different approaches for debugging Lodestar. + +## VS Code launch config + +The simplest way to debug is to use the provided [launch.template.json](https://github.com/ChainSafe/lodestar/blob/unstable/.vscode/launch.template.json) `configurations`. Copy them as `.vscode/launch.json` and they will be made available in the `Run and Debug` section in VS Code. Adapt as needed, e.g. by adding additional arguments to the beacon [configuration](https://github.com/ChainSafe/lodestar/blob/unstable/.vscode/launch.template.json#L22) to match your needs. + +VS Code supports debugging Workers out of the box when using those configurations. + +## Attach to running process + +Remote `lodestar` processes can also be debugged by leveraging [node:inspector](https://nodejs.org/api/inspector.html). Adding `--inspect` to the node CLI (e.g. `NODE_OPTIONS=--inspect ./lodestar beacon`) allows to debug the main thread. To debug a specific `Worker`, follow those steps: + +- remove `--inspect` from `node` CLI +- add following code to the `worker` + +```js +import inspector from "node:inspector"; +inspector.open(); +inspector.waitForDebugger(); +``` + +Use VS Code or Chrome devtools to debug those processes. diff --git a/docs/pages/tools/flamegraphs.md b/docs/pages/tools/flamegraphs.md index eff71ed946d7..10fe0c707dd3 100644 --- a/docs/pages/tools/flamegraphs.md +++ b/docs/pages/tools/flamegraphs.md @@ -108,11 +108,11 @@ yarn dev Then navigate in a browser to `http://localhost:8080` and begin analyzing the data. -flamescope home screen -flamescope home screen -flamescope home screen -flamescope home screen -flamescope home screen +![flamescope home screen](/images/flamescope/home-screen.png) +![flamescope time series view](/images/flamescope/time-series-view.png) +![flamescope selecting series](/images/flamescope/selecting-series.png) +![flamescope unfiltered flamegraph](/images/flamescope/unfiltered-flamegraph.png) +![flamescope zoom in](/images/flamescope/zoom-in.png) ## Filtering Results @@ -124,11 +124,11 @@ sed -r -e "/( __libc_start| uv_| LazyCompile | v8::internal::| node::| Builtins_ ### Unfiltered -flamescope home screen +![flamescope unfiltered flamegraph](/images/flamescope/unfiltered-flamegraph.png) ### Filtered -flamescope home screen +![flamescope filtered flamegraph](/images/flamescope/filtered-flamegraph.png) ## References diff --git a/docs/pages/tools/heap-dumps.md b/docs/pages/tools/heap-dumps.md index ece8f8f54b77..97f2be51dfac 100644 --- a/docs/pages/tools/heap-dumps.md +++ b/docs/pages/tools/heap-dumps.md @@ -34,15 +34,15 @@ curl -X POST http://localhost:9596/eth/v1/lodestar/write_heapdump?dirpath=/some/ It is best to analyze on a local development machine so if Lodestar is running on a cloud instance download the dump to the local environment. Open Chrome, or any Chromium based browser (the example photos were taken using Brave). In the url bar type `chrome:://inspect` to bring up the DevTools menu (in brave the url will be rewritten to `brave://inspect`). -![DevTools](../../images/heap-dumps/devtools.png) +![DevTools](/images/heap-dumps/devtools.png) Click on the `Open dedicated DevTools for Node` link to open the node specific window and click on the `Memory` tab as shown below. -![Memory Tab](../../images/heap-dumps/memory-tab.png) +![Memory Tab](/images/heap-dumps/memory-tab.png) Load the profile by either right clicking on the left pane or by clicking the `Load` button at the bottom. -![Load Profile](../../images/heap-dumps/load-profile.png) +![Load Profile](/images/heap-dumps/load-profile.png) ### Analyzing a `V8` heap dump @@ -105,7 +105,7 @@ $ git clone https://github.com/nodejs/node.git $ cd node # Use whichever version of node you prefer -$ git checkout v20.10.0 +$ git checkout v22.1.0 $ ./configure --debug # This command only builds the debug version of node and assumes diff --git a/docs/sidebars.ts b/docs/sidebars.ts index 30ef55c60b81..c33dd65c3d0b 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -4,6 +4,11 @@ const sidebars: SidebarsConfig = { tutorialSidebar: [ "index", "introduction", + { + type: "doc", + label: "Security", + id: "security", + }, { type: "category", label: "Getting Started", @@ -37,7 +42,19 @@ const sidebars: SidebarsConfig = { { type: "category", label: "Light Client and Prover", - items: ["lightclient-prover/lightclient-cli", "lightclient-prover/lightclient", "lightclient-prover/prover"], + items: [ + "lightclient-prover/lightclient-cli", + { + type: "doc", + label: "Light Client", + id: "lightclient-prover/lightclient", + }, + { + type: "doc", + label: "Prover", + id: "lightclient-prover/prover", + }, + ], }, { type: "category", @@ -49,7 +66,17 @@ const sidebars: SidebarsConfig = { type: "category", label: "Contributing", items: [ + { + type: "doc", + label: "Getting Started", + id: "contribution/getting-started", + }, "contribution/depgraph", + { + type: "doc", + label: "Dev CLI Reference", + id: "contribution/dev-cli", + }, { type: "category", label: "Testing", @@ -67,7 +94,7 @@ const sidebars: SidebarsConfig = { { type: "category", label: "Tools", - items: ["tools/flamegraphs", "tools/heap-dumps", "tools/core-dumps"], + items: ["tools/debugging", "tools/flamegraphs", "tools/heap-dumps", "tools/core-dumps"], }, { type: "category", diff --git a/docs/static/img/favicon.ico b/docs/static/images/favicon.ico similarity index 100% rename from docs/static/img/favicon.ico rename to docs/static/images/favicon.ico diff --git a/docs/images/flamescope/filtered-flamegraph.png b/docs/static/images/flamescope/filtered-flamegraph.png similarity index 100% rename from docs/images/flamescope/filtered-flamegraph.png rename to docs/static/images/flamescope/filtered-flamegraph.png diff --git a/docs/images/flamescope/home-screen.png b/docs/static/images/flamescope/home-screen.png similarity index 100% rename from docs/images/flamescope/home-screen.png rename to docs/static/images/flamescope/home-screen.png diff --git a/docs/images/flamescope/selecting-series.png b/docs/static/images/flamescope/selecting-series.png similarity index 100% rename from docs/images/flamescope/selecting-series.png rename to docs/static/images/flamescope/selecting-series.png diff --git a/docs/images/flamescope/time-series-view.png b/docs/static/images/flamescope/time-series-view.png similarity index 100% rename from docs/images/flamescope/time-series-view.png rename to docs/static/images/flamescope/time-series-view.png diff --git a/docs/images/flamescope/unfiltered-flamegraph.png b/docs/static/images/flamescope/unfiltered-flamegraph.png similarity index 100% rename from docs/images/flamescope/unfiltered-flamegraph.png rename to docs/static/images/flamescope/unfiltered-flamegraph.png diff --git a/docs/images/flamescope/zoom-in.png b/docs/static/images/flamescope/zoom-in.png similarity index 100% rename from docs/images/flamescope/zoom-in.png rename to docs/static/images/flamescope/zoom-in.png diff --git a/docs/images/gitflow-lodestar.png b/docs/static/images/gitflow-lodestar.png similarity index 100% rename from docs/images/gitflow-lodestar.png rename to docs/static/images/gitflow-lodestar.png diff --git a/docs/images/heap-dumps/devtools.png b/docs/static/images/heap-dumps/devtools.png similarity index 100% rename from docs/images/heap-dumps/devtools.png rename to docs/static/images/heap-dumps/devtools.png diff --git a/docs/images/heap-dumps/load-profile.png b/docs/static/images/heap-dumps/load-profile.png similarity index 100% rename from docs/images/heap-dumps/load-profile.png rename to docs/static/images/heap-dumps/load-profile.png diff --git a/docs/images/heap-dumps/memory-tab.png b/docs/static/images/heap-dumps/memory-tab.png similarity index 100% rename from docs/images/heap-dumps/memory-tab.png rename to docs/static/images/heap-dumps/memory-tab.png diff --git a/docs/images/lodestar-releases.png b/docs/static/images/lodestar-releases.png similarity index 100% rename from docs/images/lodestar-releases.png rename to docs/static/images/lodestar-releases.png diff --git a/docs/static/img/logo.png b/docs/static/images/logo.png similarity index 100% rename from docs/static/img/logo.png rename to docs/static/images/logo.png diff --git a/lerna.json b/lerna.json index 72851c4f3189..582c64a0d681 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.18.1", + "version": "1.19.0", "stream": true, "command": { "version": { diff --git a/package.json b/package.json index 920d4c4db135..96e4b6166ca7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "root", "private": true, "engines": { - "node": ">=20.1.0 <21" + "node": ">=20.1.0 <21 || >=22 <23" }, "workspaces": [ "packages/*" @@ -48,11 +48,11 @@ "@chainsafe/eslint-plugin-node": "^11.2.3", "@dapplion/benchmark": "^0.2.4", "@types/mocha": "^10.0.6", - "@types/node": "^20.11.28", + "@types/node": "^20.12.8", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", - "@vitest/coverage-v8": "^1.4.0", - "@vitest/browser": "^1.4.0", + "@vitest/browser": "^1.6.0", + "@vitest/coverage-v8": "^1.6.0", "crypto-browserify": "^3.12.0", "dotenv": "^16.4.5", "electron": "^26.2.2", @@ -64,30 +64,34 @@ "https-browserify": "^1.0.0", "jsdom": "^23.0.1", "lerna": "^7.3.0", - "libp2p": "1.1.1", + "libp2p": "1.4.3", "mocha": "^10.2.0", "node-gyp": "^9.4.0", "npm-run-all": "^4.1.5", "path-browserify": "^1.0.1", "prettier": "^3.2.5", "process": "^0.11.10", + "rollup-plugin-visualizer": "^5.12.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "supertest": "^6.3.3", "ts-node": "^10.9.2", "typescript": "^5.4.2", "typescript-docs-verifier": "^2.5.0", + "vite": "^5.2.11", + "vite-plugin-dts": "^3.9.1", "vite-plugin-node-polyfills": "^0.21.0", "vite-plugin-top-level-await": "^1.4.1", - "vitest": "^1.4.0", + "vitest": "^1.6.0", "vitest-when": "^0.3.1", "wait-port": "^1.1.0", - "webdriverio": "^8.34.1" + "webdriverio": "^8.36.1" }, "resolutions": { "@puppeteer/browsers": "^2.1.0", "dns-over-http-resolver": "^2.1.1", "loupe": "^2.3.6", - "vite": "^5.0.0" + "vite": "^5.2.11", + "testcontainers/**/nan": "^2.19.0" } } diff --git a/packages/api/README.md b/packages/api/README.md index 16596e91b316..39d7098d60ce 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -3,7 +3,7 @@ [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) [![ETH Beacon APIs Spec v2.1.0](https://img.shields.io/badge/ETH%20beacon--APIs-2.1.0-blue)](https://github.com/ethereum/beacon-APIs/releases/tag/v2.1.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/api/package.json b/packages/api/package.json index 4046e432a22f..ae147b5fda7c 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -69,10 +69,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.7.1", "@chainsafe/ssz": "^0.15.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, @@ -80,7 +80,7 @@ "@types/eventsource": "^1.1.11", "@types/qs": "^6.9.7", "ajv": "^8.12.0", - "fastify": "^4.26.2" + "fastify": "^4.27.0" }, "keywords": [ "ethereum", diff --git a/packages/api/src/beacon/index.ts b/packages/api/src/beacon/index.ts index d07f6f4bed53..7f0e10536d4d 100644 --- a/packages/api/src/beacon/index.ts +++ b/packages/api/src/beacon/index.ts @@ -2,7 +2,8 @@ import type {Api} from "./routes/index.js"; // NOTE: Don't export server here so it's not bundled to all consumers -export * as routes from "./routes/index.js"; +import * as routes from "./routes/index.js"; +export {routes}; export {getClient} from "./client/index.js"; export type {Api}; diff --git a/packages/api/src/beacon/routes/beacon/index.ts b/packages/api/src/beacon/routes/beacon/index.ts index 3f3d01fe17eb..95c78f45ea39 100644 --- a/packages/api/src/beacon/routes/beacon/index.ts +++ b/packages/api/src/beacon/routes/beacon/index.ts @@ -12,11 +12,7 @@ import * as rewards from "./rewards.js"; // NOTE: We choose to split the block, pool, and state namespaces so the files are not too big. // However, for a consumer all these methods are within the same service "beacon" - -export * as block from "./block.js"; -export * as pool from "./pool.js"; -export * as state from "./state.js"; -export * as rewards from "./rewards.js"; +export {block, pool, state, rewards}; export {BroadcastValidation} from "./block.js"; export type {BlockId, BlockHeaderResponse} from "./block.js"; export type {AttestationFilters} from "./pool.js"; diff --git a/packages/api/src/beacon/routes/index.ts b/packages/api/src/beacon/routes/index.ts index 81eb0cd3276c..c3fb15f8a6a4 100644 --- a/packages/api/src/beacon/routes/index.ts +++ b/packages/api/src/beacon/routes/index.ts @@ -8,15 +8,16 @@ import {Api as NodeApi} from "./node.js"; import {Api as ProofApi} from "./proof.js"; import {Api as ValidatorApi} from "./validator.js"; -export * as beacon from "./beacon/index.js"; -export * as config from "./config.js"; -export * as debug from "./debug.js"; -export * as events from "./events.js"; -export * as lightclient from "./lightclient.js"; -export * as lodestar from "./lodestar.js"; -export * as node from "./node.js"; -export * as proof from "./proof.js"; -export * as validator from "./validator.js"; +import * as beacon from "./beacon/index.js"; +import * as config from "./config.js"; +import * as debug from "./debug.js"; +import * as events from "./events.js"; +import * as lightclient from "./lightclient.js"; +import * as lodestar from "./lodestar.js"; +import * as node from "./node.js"; +import * as proof from "./proof.js"; +import * as validator from "./validator.js"; +export {beacon, config, debug, events, lightclient, lodestar, node, proof, validator}; export type Api = { beacon: BeaconApi; diff --git a/packages/api/src/beacon/server/beacon.ts b/packages/api/src/beacon/server/beacon.ts index c71decd1ac8e..cd1ed72fb586 100644 --- a/packages/api/src/beacon/server/beacon.ts +++ b/packages/api/src/beacon/server/beacon.ts @@ -22,8 +22,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR handler: async (req) => { const response = await api.getBlock(...reqSerializers.getBlock.parseReq(req)); if (response instanceof Uint8Array) { - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; } else { return returnTypes.getBlock.toJson(response); } @@ -37,8 +37,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR const slot = extractSlotFromBlockBytes(response); const version = config.getForkName(slot); void res.header("Eth-Consensus-Version", version); - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; } else { void res.header("Eth-Consensus-Version", response.version); return returnTypes.getBlockV2.toJson(response); diff --git a/packages/api/src/beacon/server/debug.ts b/packages/api/src/beacon/server/debug.ts index 34edf91a5809..553e08afddd0 100644 --- a/packages/api/src/beacon/server/debug.ts +++ b/packages/api/src/beacon/server/debug.ts @@ -23,8 +23,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR handler: async (req) => { const response = await api.getState(...reqSerializers.getState.parseReq(req)); if (response instanceof Uint8Array) { - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; } else { return returnTypes.getState.toJson(response); } @@ -38,8 +38,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR const slot = extractSlotFromStateBytes(response); const version = config.getForkName(slot); void res.header("Eth-Consensus-Version", version); - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response.buffer, response.byteOffset, response.byteLength); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; } else { void res.header("Eth-Consensus-Version", response.version); return returnTypes.getStateV2.toJson(response); diff --git a/packages/api/src/beacon/server/proof.ts b/packages/api/src/beacon/server/proof.ts index a03ae472bf78..bc865626ba72 100644 --- a/packages/api/src/beacon/server/proof.ts +++ b/packages/api/src/beacon/server/proof.ts @@ -24,8 +24,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR for (let i = 0; i < leaves.length; i++) { response.set(leaves[i], i * 32); } - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; }, }, getBlockProof: { @@ -38,8 +38,8 @@ export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerR for (let i = 0; i < leaves.length; i++) { response.set(leaves[i], i * 32); } - // Fastify 3.x.x will automatically add header `Content-Type: application/octet-stream` if Buffer - return Buffer.from(response); + // Fastify 4.x.x will automatically add header `Content-Type: application/octet-stream` if TypedArray + return response; }, }, }; diff --git a/packages/beacon-node/README.md b/packages/beacon-node/README.md index 8a016236462d..92e3f38787b7 100644 --- a/packages/beacon-node/README.md +++ b/packages/beacon-node/README.md @@ -1,9 +1,9 @@ # Lodestar [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index f1a447285154..ee17ff0c0c08 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -96,12 +96,12 @@ "dependencies": { "@chainsafe/as-sha256": "^0.4.1", "@chainsafe/bls": "7.1.3", - "@chainsafe/blst": "^0.2.10", + "@chainsafe/blst": "^0.2.11", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", - "@chainsafe/libp2p-gossipsub": "^11.2.1", + "@chainsafe/libp2p-gossipsub": "^13.0.0", "@chainsafe/libp2p-identify": "^1.0.0", - "@chainsafe/libp2p-noise": "^14.1.0", + "@chainsafe/libp2p-noise": "^15.0.0", "@chainsafe/persistent-merkle-tree": "^0.7.1", "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.15.1", @@ -111,55 +111,53 @@ "@fastify/cors": "^8.2.1", "@fastify/swagger": "^8.10.0", "@fastify/swagger-ui": "^1.9.3", - "@libp2p/bootstrap": "^10.0.10", - "@libp2p/identify": "^1.0.9", - "@libp2p/interface": "^1.1.1", - "@libp2p/mdns": "^10.0.10", - "@libp2p/mplex": "^10.0.10", - "@libp2p/peer-id": "^4.0.4", - "@libp2p/peer-id-factory": "^4.0.3", - "@libp2p/prometheus-metrics": "^3.0.10", - "@libp2p/tcp": "9.0.10", - "@lodestar/api": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/db": "^1.18.1", - "@lodestar/fork-choice": "^1.18.1", - "@lodestar/light-client": "^1.18.1", - "@lodestar/logger": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/reqresp": "^1.18.1", - "@lodestar/state-transition": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", - "@lodestar/validator": "^1.18.1", + "@libp2p/bootstrap": "^10.0.21", + "@libp2p/identify": "^1.0.20", + "@libp2p/interface": "^1.3.0", + "@libp2p/mdns": "^10.0.21", + "@libp2p/mplex": "^10.0.21", + "@libp2p/peer-id": "^4.1.0", + "@libp2p/peer-id-factory": "^4.1.0", + "@libp2p/prometheus-metrics": "^3.0.21", + "@libp2p/tcp": "9.0.23", + "@lodestar/api": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/db": "^1.19.0", + "@lodestar/fork-choice": "^1.19.0", + "@lodestar/light-client": "^1.19.0", + "@lodestar/logger": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/reqresp": "^1.19.0", + "@lodestar/state-transition": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", + "@lodestar/validator": "^1.19.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", "datastore-core": "^9.1.1", "datastore-level": "^10.1.1", "deepmerge": "^4.3.1", - "fastify": "^4.26.2", + "fastify": "^4.27.0", "interface-datastore": "^8.2.7", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "jwt-simple": "0.5.6", - "libp2p": "1.1.1", + "libp2p": "1.4.3", "multiformats": "^11.0.1", "prom-client": "^15.1.0", "qs": "^6.11.1", "snappyjs": "^0.7.0", "strict-event-emitter-types": "^2.0.0", - "systeminformation": "^5.17.12", + "systeminformation": "^5.22.9", "uint8arraylist": "^2.4.7", "xxhash-wasm": "1.0.2" }, "devDependencies": { "@types/datastore-level": "^3.0.0", - "@types/leveldown": "^4.0.3", "@types/qs": "^6.9.7", "@types/tmp": "^0.2.3", "it-drain": "^3.0.3", "it-pair": "^2.0.6", - "leveldown": "^6.1.1", "rewiremock": "^3.14.5", "rimraf": "^4.4.1", "tmp": "^0.2.1" diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts index 7a52415b0996..ed0224fc9cb6 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -4,7 +4,7 @@ import {computeEpochAtSlot, computeTimeAtSlot, reconstructFullBlockOrContents} f import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {sleep, toHex} from "@lodestar/utils"; import {allForks, deneb, isSignedBlockContents, ProducedBlockSource} from "@lodestar/types"; -import {BlockSource, getBlockInput, ImportBlockOpts, BlockInput} from "../../../../chain/blocks/types.js"; +import {BlockSource, getBlockInput, ImportBlockOpts, BlockInput, BlobsSource} from "../../../../chain/blocks/types.js"; import {promiseAllMaybeAsync} from "../../../../util/promises.js"; import {isOptimisticBlock} from "../../../../util/forkChoice.js"; import {computeBlobSidecars} from "../../../../util/blobs.js"; @@ -52,6 +52,7 @@ export function getBeaconBlockApi({ signedBlock, BlockSource.api, blobSidecars, + BlobsSource.api, // don't bundle any bytes for block and blobs null, blobSidecars.map(() => null) diff --git a/packages/beacon-node/src/api/rest/base.ts b/packages/beacon-node/src/api/rest/base.ts index dbf69cd0d014..86eab0ba46d4 100644 --- a/packages/beacon-node/src/api/rest/base.ts +++ b/packages/beacon-node/src/api/rest/base.ts @@ -1,5 +1,5 @@ import {parse as parseQueryString} from "qs"; -import {FastifyInstance, FastifyRequest, fastify} from "fastify"; +import {FastifyInstance, FastifyRequest, fastify, errorCodes} from "fastify"; import {fastifyCors} from "@fastify/cors"; import bearerAuthPlugin from "@fastify/bearer-auth"; import {ErrorAborted, Gauge, Histogram, Logger} from "@lodestar/utils"; @@ -28,6 +28,11 @@ export type RestApiServerMetrics = SocketMetrics & { errors: Gauge<{operationId: string}>; }; +/** + * Error code used by Fastify if media type is not supported (415) + */ +const INVALID_MEDIA_TYPE_CODE = errorCodes.FST_ERR_CTP_INVALID_MEDIA_TYPE().code; + /** * REST API powered by `fastify` server. */ @@ -107,7 +112,7 @@ export class RestApiServer { const operationId = getOperationId(req); - if (err instanceof ApiError) { + if (err instanceof ApiError || err.code === INVALID_MEDIA_TYPE_CODE) { this.logger.warn(`Req ${req.id} ${operationId} failed`, {reason: err.message}); } else { this.logger.error(`Req ${req.id} ${operationId} error`, {}, err); @@ -159,6 +164,5 @@ export class RestApiServer { } function getOperationId(req: FastifyRequest): string { - // Note: `schema` will be `undefined` if route is not defined return req.routeOptions.schema?.operationId ?? "unknown"; } diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index d82448a4e932..4d0dcb341481 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -19,6 +19,7 @@ import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; import {ChainEvent, ReorgEventData} from "../emitter.js"; import {REPROCESS_MIN_TIME_TO_NEXT_SLOT_SEC} from "../reprocess.js"; import type {BeaconChain} from "../chain.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {FullyVerifiedBlock, ImportBlockOpts, AttestationImportOpt, BlockInputType} from "./types.js"; import {getCheckpointFromState} from "./utils/checkpoint.js"; import {writeBlockInputToDb} from "./writeBlockInputToDb.js"; @@ -69,6 +70,11 @@ export async function importBlock( const blockDelaySec = (fullyVerifiedBlock.seenTimestampSec - postState.genesisTime) % this.config.SECONDS_PER_SLOT; const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000); + // this is just a type assertion since blockinput with blobsPromise type will not end up here + if (blockInput.type === BlockInputType.blobsPromise) { + throw Error("Unavailable block can not be imported in forkchoice"); + } + // 1. Persist block to hot DB (pre-emptively) // If eagerPersistBlock = true we do that in verifyBlocksInEpoch to batch all I/O operations to save block time to head if (!opts.eagerPersistBlock) { @@ -95,15 +101,21 @@ export async function importBlock( this.logger.verbose("Added block to forkchoice and state cache", {slot: blockSlot, root: blockRootHex}); // We want to import block asap so call all event handler in the next event loop - setTimeout(() => { + callInNextEventLoop(async () => { this.emitter.emit(routes.events.EventType.block, { block: blockRootHex, slot: blockSlot, executionOptimistic: blockSummary != null && isOptimisticBlock(blockSummary), }); + // blobsPromise will not end up here, but preDeneb could. In future we might also allow syncing + // out of data range blocks and import then in forkchoice although one would not be able to + // attest and propose with such head similar to optimistic sync if (blockInput.type === BlockInputType.postDeneb) { - for (const blobSidecar of blockInput.blobs) { + const {blobsSource, blobs} = blockInput; + + this.metrics?.importBlock.blobsBySource.inc({blobsSource}); + for (const blobSidecar of blobs) { const {index, kzgCommitment} = blobSidecar; this.emitter.emit(routes.events.EventType.blobSidecar, { blockRoot: blockRootHex, @@ -114,7 +126,7 @@ export async function importBlock( }); } } - }, 0); + }); // 3. Import attestations to fork choice // @@ -290,7 +302,7 @@ export async function importBlock( // - Use block's syncAggregate if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) { // we want to import block asap so do this in the next event loop - setTimeout(() => { + callInNextEventLoop(() => { try { this.lightClientServer.onImportBlockHead( block.message as allForks.AllForksLightClient["BeaconBlock"], @@ -300,7 +312,7 @@ export async function importBlock( } catch (e) { this.logger.verbose("Error lightClientServer.onImportBlock", {slot: blockSlot}, e as Error); } - }, 0); + }); } } @@ -444,9 +456,9 @@ export async function importBlock( // Gossip blocks need to be imported as soon as possible, waiting attestations could be processed // in the next event loop. See https://github.com/ChainSafe/lodestar/issues/4789 - setTimeout(() => { + callInNextEventLoop(() => { this.reprocessController.onBlockImported({slot: blockSlot, root: blockRootHex}, advancedSlot); - }, 0); + }); if (opts.seenTimestampSec !== undefined) { const recvToValidation = Date.now() / 1000 - opts.seenTimestampSec; diff --git a/packages/beacon-node/src/chain/blocks/index.ts b/packages/beacon-node/src/chain/blocks/index.ts index 8f4c7fa5f0f1..12450fe85f94 100644 --- a/packages/beacon-node/src/chain/blocks/index.ts +++ b/packages/beacon-node/src/chain/blocks/index.ts @@ -68,7 +68,7 @@ export async function processBlocks( // Fully verify a block to be imported immediately after. Does not produce any side-effects besides adding intermediate // states in the state cache through regen. - const {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus} = + const {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, availableBlockInputs} = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, opts); // If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid @@ -81,7 +81,7 @@ export async function processBlocks( } const {executionStatuses} = segmentExecStatus; - const fullyVerifiedBlocks = relevantBlocks.map( + const fullyVerifiedBlocks = availableBlockInputs.map( (block, i): FullyVerifiedBlock => ({ blockInput: block, postState: postStates[i], diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index e2c7b5a32e0a..170ebd8a5a0c 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -18,13 +18,21 @@ export enum BlockSource { byRoot = "req_resp_by_root", } +/** Enum to represent where blobs come from */ +export enum BlobsSource { + gossip = "gossip", + api = "api", + byRange = "req_resp_by_range", + byRoot = "req_resp_by_root", +} + export enum GossipedInputType { block = "block", blob = "blob", } export type BlobsCache = Map; -export type BlockInputBlobs = {blobs: deneb.BlobSidecars; blobsBytes: (Uint8Array | null)[]}; +export type BlockInputBlobs = {blobs: deneb.BlobSidecars; blobsBytes: (Uint8Array | null)[]; blobsSource: BlobsSource}; type CachedBlobs = { blobsCache: BlobsCache; availabilityPromise: Promise; @@ -34,6 +42,7 @@ type CachedBlobs = { export type BlockInput = {block: allForks.SignedBeaconBlock; source: BlockSource; blockBytes: Uint8Array | null} & ( | {type: BlockInputType.preDeneb} | ({type: BlockInputType.postDeneb} & BlockInputBlobs) + // the blobsSource here is added to BlockInputBlobs when availability is resolved | ({type: BlockInputType.blobsPromise} & CachedBlobs) ); export type NullBlockInput = {block: null; blockRootHex: RootHex; blockInputPromise: Promise} & CachedBlobs; @@ -69,6 +78,7 @@ export const getBlockInput = { block: allForks.SignedBeaconBlock, source: BlockSource, blobs: deneb.BlobSidecars, + blobsSource: BlobsSource, blockBytes: Uint8Array | null, blobsBytes: (Uint8Array | null)[] ): BlockInput { @@ -80,6 +90,7 @@ export const getBlockInput = { block, source, blobs, + blobsSource, blockBytes, blobsBytes, }; @@ -109,7 +120,7 @@ export const getBlockInput = { }, }; -export function getBlockInputBlobs(blobsCache: BlobsCache): BlockInputBlobs { +export function getBlockInputBlobs(blobsCache: BlobsCache): Omit { const blobs = []; const blobsBytes = []; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index 658ac05d3908..9bb7192b2820 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -45,6 +45,7 @@ export async function verifyBlocksInEpoch( proposerBalanceDeltas: number[]; segmentExecStatus: SegmentExecStatus; dataAvailabilityStatuses: DataAvailableStatus[]; + availableBlockInputs: BlockInput[]; }> { const blocks = blocksInput.map(({block}) => block); if (blocks.length === 0) { @@ -92,7 +93,7 @@ export async function verifyBlocksInEpoch( // batch all I/O operations to reduce overhead const [ segmentExecStatus, - {dataAvailabilityStatuses, availableTime}, + {dataAvailabilityStatuses, availableTime, availableBlockInputs}, {postStates, proposerBalanceDeltas, verifyStateTime}, {verifySignaturesTime}, ] = await Promise.all([ @@ -190,7 +191,7 @@ export async function verifyBlocksInEpoch( } } - return {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus}; + return {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, availableBlockInputs}; } finally { abortController.abort(); } diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts index de7a9575ce06..f995dde967bd 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts @@ -5,7 +5,7 @@ import {Logger} from "@lodestar/utils"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {validateBlobSidecars} from "../validation/blobSidecar.js"; import {Metrics} from "../../metrics/metrics.js"; -import {BlockInput, BlockInputType, ImportBlockOpts, BlobSidecarValidation} from "./types.js"; +import {BlockInput, BlockInputType, ImportBlockOpts, BlobSidecarValidation, getBlockInput} from "./types.js"; // we can now wait for full 12 seconds because unavailable block sync will try pulling // the blobs from the network anyway after 500ms of seeing the block @@ -27,7 +27,11 @@ export async function verifyBlocksDataAvailability( chain: {config: ChainForkConfig; genesisTime: UintNum64; logger: Logger; metrics: Metrics | null}, blocks: BlockInput[], opts: ImportBlockOpts -): Promise<{dataAvailabilityStatuses: DataAvailableStatus[]; availableTime: number}> { +): Promise<{ + dataAvailabilityStatuses: DataAvailableStatus[]; + availableTime: number; + availableBlockInputs: BlockInput[]; +}> { if (blocks.length === 0) { throw Error("Empty partiallyVerifiedBlocks"); } @@ -35,11 +39,14 @@ export async function verifyBlocksDataAvailability( const dataAvailabilityStatuses: DataAvailableStatus[] = []; const seenTime = opts.seenTimestampSec !== undefined ? opts.seenTimestampSec * 1000 : Date.now(); + const availableBlockInputs: BlockInput[] = []; + for (const blockInput of blocks) { // Validate status of only not yet finalized blocks, we don't need yet to propogate the status // as it is not used upstream anywhere - const dataAvailabilityStatus = await maybeValidateBlobs(chain, blockInput, opts); + const {dataAvailabilityStatus, availableBlockInput} = await maybeValidateBlobs(chain, blockInput, opts); dataAvailabilityStatuses.push(dataAvailabilityStatus); + availableBlockInputs.push(availableBlockInput); } const availableTime = blocks[blocks.length - 1].type === BlockInputType.blobsPromise ? Date.now() : seenTime; @@ -55,21 +62,21 @@ export async function verifyBlocksDataAvailability( }); } - return {dataAvailabilityStatuses, availableTime}; + return {dataAvailabilityStatuses, availableTime, availableBlockInputs}; } async function maybeValidateBlobs( chain: {config: ChainForkConfig; genesisTime: UintNum64; logger: Logger}, blockInput: BlockInput, opts: ImportBlockOpts -): Promise { +): Promise<{dataAvailabilityStatus: DataAvailableStatus; availableBlockInput: BlockInput}> { switch (blockInput.type) { case BlockInputType.preDeneb: - return DataAvailableStatus.preDeneb; + return {dataAvailabilityStatus: DataAvailableStatus.preDeneb, availableBlockInput: blockInput}; case BlockInputType.postDeneb: if (opts.validBlobSidecars === BlobSidecarValidation.Full) { - return DataAvailableStatus.available; + return {dataAvailabilityStatus: DataAvailableStatus.available, availableBlockInput: blockInput}; } // eslint-disable-next-line no-fallthrough @@ -82,7 +89,7 @@ async function maybeValidateBlobs( blockInput.type === BlockInputType.postDeneb ? blockInput : await raceWithCutoff(chain, blockInput, blockInput.availabilityPromise); - const {blobs} = blobsData; + const {blobs, blobsBytes, blobsSource} = blobsData; const {blobKzgCommitments} = (block as deneb.SignedBeaconBlock).message.body; const beaconBlockRoot = chain.config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message); @@ -92,7 +99,16 @@ async function maybeValidateBlobs( const skipProofsCheck = opts.validBlobSidecars === BlobSidecarValidation.Individual; validateBlobSidecars(blockSlot, beaconBlockRoot, blobKzgCommitments, blobs, {skipProofsCheck}); - return DataAvailableStatus.available; + const availableBlockInput = getBlockInput.postDeneb( + chain.config, + blockInput.block, + blockInput.source, + blobs, + blobsSource, + blockInput.blockBytes, + blobsBytes + ); + return {dataAvailabilityStatus: DataAvailableStatus.available, availableBlockInput: availableBlockInput}; } } } diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts index 8f386ef191d2..ed3e27551b88 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts @@ -305,12 +305,16 @@ export async function verifyBlockExecutionPayload( ? (block.message.body as deneb.BeaconBlockBody).blobKzgCommitments.map(kzgCommitmentToVersionedHash) : undefined; const parentBlockRoot = ForkSeq[fork] >= ForkSeq.deneb ? block.message.parentRoot : undefined; + + const logCtx = {slot: block.message.slot, executionBlock: executionPayloadEnabled.blockNumber}; + chain.logger.debug("Call engine api newPayload", logCtx); const execResult = await chain.executionEngine.notifyNewPayload( fork, executionPayloadEnabled, versionedHashes, parentBlockRoot ); + chain.logger.debug("Receive engine api newPayload result", {...logCtx, status: execResult.status}); chain.metrics?.engineNotifyNewPayloadResult.inc({result: execResult.status}); diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts index ff0b19ee3edc..6c66b5d74c4c 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts @@ -1,9 +1,10 @@ import {CachedBeaconStateAllForks, getBlockSignatureSets} from "@lodestar/state-transition"; import {allForks} from "@lodestar/types"; -import {Logger, sleep} from "@lodestar/utils"; +import {Logger} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {IBlsVerifier} from "../bls/index.js"; import {BlockError, BlockErrorCode} from "../errors/blockError.js"; +import {nextEventLoop} from "../../util/eventLoop.js"; import {ImportBlockOpts} from "./types.js"; /** @@ -40,10 +41,10 @@ export async function verifyBlocksSignatures( ); // getBlockSignatureSets() takes 45ms in benchmarks for 2022Q2 mainnet blocks (100 sigs). When syncing a 32 blocks - // segments it will block the event loop for 1400 ms, which is too much. This sleep will allow the event loop to + // segments it will block the event loop for 1400 ms, which is too much. This call will allow the event loop to // yield, which will cause one block's state transition to run. However, the tradeoff is okay and doesn't slow sync if ((i + 1) % 8 === 0) { - await sleep(0); + await nextEventLoop(); } } diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts index 62d5f6802533..49cd46220008 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts @@ -5,11 +5,12 @@ import { DataAvailableStatus, StateHashTreeRootSource, } from "@lodestar/state-transition"; -import {ErrorAborted, Logger, sleep} from "@lodestar/utils"; +import {ErrorAborted, Logger} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {BlockProcessOpts} from "../options.js"; import {byteArrayEquals} from "../../util/bytes.js"; +import {nextEventLoop} from "../../util/eventLoop.js"; import {BlockInput, ImportBlockOpts} from "./types.js"; /** @@ -90,7 +91,7 @@ export async function verifyBlocksStateTransitionOnly( // this avoids keeping our node busy processing blocks if (i < blocks.length - 1) { - await sleep(0); + await nextEventLoop(); } } diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index 2d1179a50ef4..23e6f1bb460b 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -17,6 +17,7 @@ import {IBlsVerifier, VerifySignatureOpts} from "../interface.js"; import {getAggregatedPubkey, getAggregatedPubkeysCount} from "../utils.js"; import {verifySignatureSetsMaybeBatch} from "../maybeBatch.js"; import {LinkedList} from "../../../util/array.js"; +import {callInNextEventLoop} from "../../../util/eventLoop.js"; import {BlsWorkReq, BlsWorkResult, WorkerData, WorkResultCode, WorkResultError} from "./types.js"; import {chunkifyMaximizeChunkSize} from "./utils.js"; import {defaultPoolSize} from "./poolSize.js"; @@ -352,7 +353,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { } else { this.jobs.push(job); } - setTimeout(this.runJob, 0); + callInNextEventLoop(this.runJob); } } @@ -515,7 +516,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { this.workersBusy--; // Potentially run a new job - setTimeout(this.runJob, 0); + callInNextEventLoop(this.runJob); }; /** @@ -550,7 +551,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { this.jobs.unshift(job); } this.bufferedJobs = null; - setTimeout(this.runJob, 0); + callInNextEventLoop(this.runJob); } }; diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index f57c37cc95a5..3fe6f08e1383 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -10,7 +10,7 @@ import { stateTransition, } from "@lodestar/state-transition"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {Logger, sleep} from "@lodestar/utils"; +import {Logger} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; import {Metrics} from "../../metrics/index.js"; @@ -18,6 +18,7 @@ import {IBeaconDb} from "../../db/index.js"; import {getCheckpointFromState} from "../blocks/utils/checkpoint.js"; import {ChainEvent, ChainEventEmitter} from "../emitter.js"; import {CheckpointStateCache, BlockStateCache} from "../stateCache/types.js"; +import {nextEventLoop} from "../../util/eventLoop.js"; import {IStateRegeneratorInternal, RegenCaller, StateCloneOpts} from "./interface.js"; import {RegenError, RegenErrorCode} from "./errors.js"; @@ -239,7 +240,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { } // this avoids keeping our node busy processing blocks - await sleep(0); + await nextEventLoop(); } catch (e) { throw new RegenError({ code: RegenErrorCode.STATE_TRANSITION_ERROR, @@ -325,7 +326,7 @@ async function processSlotsToNearestCheckpoint( emitter.emit(ChainEvent.checkpoint, cp, checkpointState.clone(true)); // this avoids keeping our node busy processing blocks - await sleep(0); + await nextEventLoop(); } return postState; } diff --git a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts index c652eaad9a9b..77976b70e6e8 100644 --- a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts +++ b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts @@ -13,6 +13,7 @@ import { BlobsCache, GossipedInputType, getBlockInputBlobs, + BlobsSource, } from "../blocks/types.js"; import {Metrics} from "../../metrics/index.js"; @@ -135,7 +136,7 @@ export class SeenGossipBlockInput { if (blobKzgCommitments.length === blobsCache.size) { const allBlobs = getBlockInputBlobs(blobsCache); - resolveAvailability(allBlobs); + resolveAvailability({...allBlobs, blobsSource: BlobsSource.gossip}); metrics?.syncUnknownBlock.resolveAvailabilitySource.inc({source: BlockInputAvailabilitySource.GOSSIP}); const {blobs, blobsBytes} = allBlobs; const blockInput = getBlockInput.postDeneb( @@ -143,6 +144,7 @@ export class SeenGossipBlockInput { signedBlock, BlockSource.gossip, blobs, + BlobsSource.gossip, blockBytes ?? null, blobsBytes ); diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 170e7421024e..430464683493 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -127,6 +127,9 @@ async function validateAggregateAndProof( // and non-gossip sources) (a client MAY queue attestations for processing once block is retrieved). // Lighthouse doesn't check maxSkipSlots option here but Lodestar wants to be more strict // to be more DOS protection + + // [REJECT] The aggregate attestation's target block is an ancestor of the block named in the LMD vote + // -- i.e. `get_checkpoint_block(store, aggregate.data.beacon_block_root, aggregate.data.target.epoch) == aggregate.data.target.root` const attHeadBlock = verifyHeadBlockAndTargetRoot( chain, attData.beaconBlockRoot, @@ -148,10 +151,17 @@ async function validateAggregateAndProof( RegenCaller.validateGossipAttestation ); + // [REJECT] The committee index is within the expected range + // -- i.e. data.index < get_committee_count_per_slot(state, data.target.epoch) const committeeIndices = cachedAttData ? cachedAttData.committeeIndices : getCommitteeIndices(shuffling, attSlot, attIndex); + // [REJECT] The number of aggregation bits matches the committee size + // -- i.e. `len(aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, index))`. + if (aggregate.aggregationBits.bitLen !== committeeIndices.length) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS}); + } const attestingIndices = aggregate.aggregationBits.intersectValues(committeeIndices); const indexedAttestation: phase0.IndexedAttestation = { attestingIndices, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 20dc0333989a..12b7f3538d6e 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1,6 +1,6 @@ import {EpochTransitionStep, StateCloneSource, StateHashTreeRootSource} from "@lodestar/state-transition"; import {allForks} from "@lodestar/types"; -import {BlockSource} from "../../chain/blocks/types.js"; +import {BlockSource, BlobsSource} from "../../chain/blocks/types.js"; import {JobQueueItemType} from "../../chain/bls/index.js"; import {BlockErrorCode} from "../../chain/errors/index.js"; import {InsertOutcome} from "../../chain/opPools/types.js"; @@ -800,6 +800,11 @@ export function createLodestarMetrics( help: "Total number of imported blocks by source", labelNames: ["source"], }), + blobsBySource: register.gauge<{blobsSource: BlobsSource}>({ + name: "lodestar_import_blobs_by_source_total", + help: "Total number of imported blobs by source", + labelNames: ["blobsSource"], + }), }, engineNotifyNewPayloadResult: register.gauge<{result: ExecutionPayloadStatus}>({ name: "lodestar_execution_engine_notify_new_payload_result_total", diff --git a/packages/beacon-node/src/monitoring/clientStats.ts b/packages/beacon-node/src/monitoring/clientStats.ts index 185d03428c8c..fe512bf0d71f 100644 --- a/packages/beacon-node/src/monitoring/clientStats.ts +++ b/packages/beacon-node/src/monitoring/clientStats.ts @@ -66,7 +66,7 @@ function createProcessStats(process: ProcessType): ClientStats { clientName: new StaticProperty({ jsonKey: "client_name", value: CLIENT_NAME, - description: "Name of client, e.g. lodestar, prysm, lighthouse, teku, nimbus", + description: "Name of client, e.g. lodestar, prysm, lighthouse, teku, nimbus, grandine", }), clientVersion: new MetricProperty({ jsonKey: "client_version", diff --git a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts index 2b6c85afa1f8..19cca27eaaac 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts @@ -3,7 +3,7 @@ import workerThreads from "node:worker_threads"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {ModuleThread, Thread, Worker, spawn} from "@chainsafe/threads"; -import {PeerId} from "@libp2p/interface"; +import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; import {exportToProtobuf} from "@libp2p/peer-id-factory"; import {routes} from "@lodestar/api"; import {BeaconConfig, chainConfigToJson} from "@lodestar/config"; @@ -110,7 +110,7 @@ export class WorkerNetworkCore implements INetworkCore { opts, chainConfigJson: chainConfigToJson(config), genesisValidatorsRoot: config.genesisValidatorsRoot, - peerIdProto: exportToProtobuf(peerId), + peerIdProto: exportToProtobuf(peerId as Secp256k1PeerId), localMultiaddrs, metricsEnabled, peerStoreDir, diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index 97d07ed774d5..b2136658dfe7 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,5 +1,5 @@ import EventEmitter from "events"; -import {PeerId} from "@libp2p/interface"; +import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {exportToProtobuf} from "@libp2p/peer-id-factory"; import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR} from "@chainsafe/enr"; @@ -42,7 +42,7 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter { const workerData: Discv5WorkerData = { enr: opts.discv5.enr, - peerIdProto: exportToProtobuf(opts.peerId), + peerIdProto: exportToProtobuf(opts.peerId as Secp256k1PeerId), bindAddrs: opts.discv5.bindAddrs, config: opts.discv5.config ?? {}, bootEnrs: opts.discv5.bootEnrs, diff --git a/packages/beacon-node/src/network/gossip/encoding.ts b/packages/beacon-node/src/network/gossip/encoding.ts index cccb0807b101..3b87f42747ab 100644 --- a/packages/beacon-node/src/network/gossip/encoding.ts +++ b/packages/beacon-node/src/network/gossip/encoding.ts @@ -18,7 +18,7 @@ const h64Seed = BigInt(Math.floor(Math.random() * 1e9)); * The function used to generate a gossipsub message id * We use the first 8 bytes of SHA256(data) for content addressing */ -export function fastMsgIdFn(rpcMsg: RPC.IMessage): string { +export function fastMsgIdFn(rpcMsg: RPC.Message): string { if (rpcMsg.data) { return xxhash.h64Raw(rpcMsg.data, h64Seed).toString(16); } else { @@ -58,7 +58,7 @@ export function msgIdFn(gossipTopicCache: GossipTopicCache, msg: Message): Uint8 vec = [MESSAGE_DOMAIN_VALID_SNAPPY, intToBytes(msg.topic.length, 8), Buffer.from(msg.topic), msg.data]; } - return Buffer.from(digest(Buffer.concat(vec))).subarray(0, 20); + return digest(Buffer.concat(vec)).subarray(0, 20); } export class DataTransformSnappy { diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 81e3b1b67c48..4066452f1e3b 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -12,6 +12,7 @@ import {ClientKind} from "../peers/client.js"; import {GOSSIP_MAX_SIZE, GOSSIP_MAX_SIZE_BELLATRIX} from "../../constants/network.js"; import {Libp2p} from "../interface.js"; import {NetworkEvent, NetworkEventBus, NetworkEventData} from "../events.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {GossipTopic, GossipType} from "./interface.js"; import {GossipTopicCache, stringifyGossipTopic, getCoreTopicsAtFork} from "./topic.js"; import {DataTransformSnappy, fastMsgIdFn, msgIdFn, msgIdToStrFn} from "./encoding.js"; @@ -91,7 +92,7 @@ export class Eth2Gossipsub extends GossipSub { // https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub super(modules.libp2p.services.components, { globalSignaturePolicy: SignaturePolicy.StrictNoSign, - allowPublishToZeroPeers: allowPublishToZeroPeers, + allowPublishToZeroTopicPeers: allowPublishToZeroPeers, D: gossipsubD ?? GOSSIP_D, Dlo: gossipsubDLow ?? GOSSIP_D_LOW, Dhi: gossipsubDHigh ?? GOSSIP_D_HIGH, @@ -288,7 +289,7 @@ export class Eth2Gossipsub extends GossipSub { // Use setTimeout to yield to the macro queue // Without this we'll have huge event loop lag // See https://github.com/ChainSafe/lodestar/issues/5604 - setTimeout(() => { + callInNextEventLoop(() => { this.events.emit(NetworkEvent.pendingGossipsubMessage, { topic, msg, @@ -298,16 +299,16 @@ export class Eth2Gossipsub extends GossipSub { seenTimestampSec, startProcessUnixSec: null, }); - }, 0); + }); } private onValidationResult(data: NetworkEventData[NetworkEvent.gossipMessageValidationResult]): void { // Use setTimeout to yield to the macro queue // Without this we'll have huge event loop lag // See https://github.com/ChainSafe/lodestar/issues/5604 - setTimeout(() => { + callInNextEventLoop(() => { this.reportMessageValidationResult(data.msgId, data.propagationSource, data.acceptance); - }, 0); + }); } } diff --git a/packages/beacon-node/src/network/options.ts b/packages/beacon-node/src/network/options.ts index 26decc60f21d..713ca4b21ad0 100644 --- a/packages/beacon-node/src/network/options.ts +++ b/packages/beacon-node/src/network/options.ts @@ -33,6 +33,8 @@ export const defaultNetworkOptions: NetworkOptions = { discv5: null, rateLimitMultiplier: 1, useWorker: true, + // set after testing before 1.19.0, see https://github.com/ChainSafe/lodestar/issues/6596 + disableFloodPublish: true, // default set via research in https://github.com/ChainSafe/lodestar/issues/2115 maxYoungGenerationSizeMb: 152, // subscribe 2 slots before aggregator dutied slot to get stable mesh peers as monitored on goerli diff --git a/packages/beacon-node/src/network/peers/client.ts b/packages/beacon-node/src/network/peers/client.ts index 4b84233f6833..5674bee82000 100644 --- a/packages/beacon-node/src/network/peers/client.ts +++ b/packages/beacon-node/src/network/peers/client.ts @@ -4,6 +4,7 @@ export enum ClientKind { Teku = "Teku", Prysm = "Prysm", Lodestar = "Lodestar", + Grandine = "Grandine", Unknown = "Unknown", } @@ -21,6 +22,7 @@ export function getKnownClientFromAgentVersion(agentVersion: string): ClientKind if (agentLC === "teku") return ClientKind.Teku; if (agentLC === "prysm") return ClientKind.Prysm; if (agentLC === "nimbus") return ClientKind.Nimbus; + if (agentLC === "grandine") return ClientKind.Grandine; if (agentLC === "lodestar" || agentLC === "js-libp2p") return ClientKind.Lodestar; return null; diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index 420360920518..9a1dcfb32fa0 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -18,6 +18,7 @@ import { GossipValidatorFn, } from "../gossip/interface.js"; import {PeerIdStr} from "../peers/index.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {createGossipQueues} from "./gossipQueues/index.js"; import {PendingGossipsubMessage} from "./types.js"; import {ValidatorFnsModules, GossipHandlerOpts, getGossipHandlers} from "./gossipHandlers.js"; @@ -452,22 +453,22 @@ export class NetworkProcessor { if (Array.isArray(messageOrArray)) { for (const [i, msg] of messageOrArray.entries()) { - setTimeout(() => { + callInNextEventLoop(() => { this.events.emit(NetworkEvent.gossipMessageValidationResult, { msgId: msg.msgId, propagationSource: msg.propagationSource, acceptance: acceptanceArr[i], }); - }, 0); + }); } } else { - setTimeout(() => { + callInNextEventLoop(() => { this.events.emit(NetworkEvent.gossipMessageValidationResult, { msgId: messageOrArray.msgId, propagationSource: messageOrArray.propagationSource, acceptance: acceptanceArr[0], }); - }, 0); + }); } } diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index 2a20a3f1f7fd..cfe13b527183 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -21,6 +21,7 @@ import {PeersData} from "../peers/peersData.js"; import {IPeerRpcScoreStore, PeerAction} from "../peers/score/index.js"; import {NetworkCoreMetrics} from "../core/metrics.js"; import {StatusCache} from "../statusCache.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {onOutgoingReqRespError} from "./score.js"; import { GetReqRespHandlerFn, @@ -259,7 +260,7 @@ export class ReqRespBeaconNode extends ReqResp { // Allow onRequest to return and close the stream // For Goodbye there may be a race condition where the listener of `receivedGoodbye` // disconnects in the same synchronous call, preventing the stream from ending cleanly - setTimeout(() => this.networkEventBus.emit(NetworkEvent.reqRespRequest, {request, peer}), 0); + callInNextEventLoop(() => this.networkEventBus.emit(NetworkEvent.reqRespRequest, {request, peer})); } protected onIncomingRequest(peerId: PeerId, protocol: ProtocolDescriptor): void { diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index e57c3e5b7c8e..2d66584dd716 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -3,7 +3,7 @@ import {deneb, Epoch, phase0, allForks, Slot} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot} from "@lodestar/state-transition"; -import {BlockInput, BlockSource, getBlockInput} from "../../chain/blocks/types.js"; +import {BlobsSource, BlockInput, BlockSource, getBlockInput} from "../../chain/blocks/types.js"; import {PeerIdStr} from "../../util/peerId.js"; import {INetwork, WithBytes} from "../interface.js"; @@ -43,7 +43,7 @@ export async function beaconBlocksMaybeBlobsByRange( network.sendBlobSidecarsByRange(peerId, request), ]); - return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, endSlot, BlockSource.byRange); + return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, endSlot, BlockSource.byRange, BlobsSource.byRange); } // Post Deneb but old blobs @@ -58,7 +58,8 @@ export function matchBlockWithBlobs( allBlocks: WithBytes[], allBlobSidecars: deneb.BlobSidecar[], endSlot: Slot, - blockSource: BlockSource + blockSource: BlockSource, + blobsSource: BlobsSource ): BlockInput[] { const blockInputs: BlockInput[] = []; let blobSideCarIndex = 0; @@ -101,6 +102,7 @@ export function matchBlockWithBlobs( block.data, blockSource, blobSidecars, + blobsSource, null, Array.from({length: blobKzgCommitmentsLen}, () => null) ) diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index 9aa262732042..95d88f39586f 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -9,6 +9,7 @@ import { getBlockInputBlobs, getBlockInput, NullBlockInput, + BlobsSource, } from "../../chain/blocks/types.js"; import {PeerIdStr} from "../../util/peerId.js"; import {INetwork} from "../interface.js"; @@ -47,7 +48,7 @@ export async function beaconBlocksMaybeBlobsByRoot( // The last arg is to provide slot to which all blobs should be exausted in matching // and here it should be infinity since all bobs should match - return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, Infinity, BlockSource.byRoot); + return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, Infinity, BlockSource.byRoot, BlobsSource.byRoot); } export async function unavailableBeaconBlobsByRoot( @@ -104,7 +105,7 @@ export async function unavailableBeaconBlobsByRoot( throw Error(`Not all blobs fetched missingBlobs=${blobKzgCommitmentsLen - blobs.length}`); } - resolveAvailability(allBlobs); + resolveAvailability({...allBlobs, blobsSource: BlobsSource.byRoot}); metrics?.syncUnknownBlock.resolveAvailabilitySource.inc({source: BlockInputAvailabilitySource.UNKNOWN_SYNC}); - return getBlockInput.postDeneb(config, block, BlockSource.byRoot, blobs, blockBytes, blobsBytes); + return getBlockInput.postDeneb(config, block, BlockSource.byRoot, blobs, BlobsSource.byRoot, blockBytes, blobsBytes); } diff --git a/packages/beacon-node/src/util/eventLoop.ts b/packages/beacon-node/src/util/eventLoop.ts new file mode 100644 index 000000000000..bf8f94ac91b0 --- /dev/null +++ b/packages/beacon-node/src/util/eventLoop.ts @@ -0,0 +1,22 @@ +import {sleep} from "@lodestar/utils"; + +/** + * Schedules in 1ms a Promise to be resolved during the `timers` phase. + * Awaiting this Promise will force the whole event queue to be executed. + * + * Caution: as the execution of the event queue might lead to new enqueuing, this might take significant time. + */ +export function nextEventLoop(): Promise { + // `setTimeout` delay is at least 1ms + // Say https://nodejs.org/api/timers.html#settimeoutcallback-delay-args + return sleep(0); +} + +/** + * Schedules in 1ms a callback for execution during the next `timers` phase. + */ +export function callInNextEventLoop(callback: () => void): void { + // `setTimeout` delay is at least 1ms + // Say https://nodejs.org/api/timers.html#settimeoutcallback-delay-args + setTimeout(callback, 0); +} diff --git a/packages/beacon-node/src/util/queue/itemQueue.ts b/packages/beacon-node/src/util/queue/itemQueue.ts index df8c21850c7c..7da7b6cdd8cb 100644 --- a/packages/beacon-node/src/util/queue/itemQueue.ts +++ b/packages/beacon-node/src/util/queue/itemQueue.ts @@ -1,5 +1,5 @@ -import {sleep} from "@lodestar/utils"; import {LinkedList} from "../array.js"; +import {callInNextEventLoop, nextEventLoop} from "../../util/eventLoop.js"; import {QueueError, QueueErrorCode} from "./errors.js"; import {defaultQueueOpts, QueueMetrics, JobQueueOpts, QueueType} from "./options.js"; @@ -66,7 +66,7 @@ export class JobItemQueue { if (this.jobs.length === 1 && this.opts.noYieldIfOneItem) { void this.runJob(); } else if (this.runningJobs < this.opts.maxConcurrency) { - setTimeout(this.runJob, 0); + callInNextEventLoop(this.runJob); } }); } @@ -106,7 +106,7 @@ export class JobItemQueue { // Yield to the macro queue if (Date.now() - this.lastYield > this.opts.yieldEveryMs) { this.lastYield = Date.now(); - await sleep(0); + await nextEventLoop(); } } catch (e) { job.reject(e as Error); diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index cd12c4bd9c18..802b9a266ab1 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -59,9 +59,7 @@ export function getAttDataBase64FromAttestationSerialized(data: Uint8Array): Att } // base64 is a bit efficient than hex - return Buffer.from(data.slice(VARIABLE_FIELD_OFFSET, VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE)).toString( - "base64" - ); + return toBase64(data.slice(VARIABLE_FIELD_OFFSET, VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE)); } /** @@ -150,9 +148,9 @@ export function getAttDataBase64FromSignedAggregateAndProofSerialized(data: Uint } // base64 is a bit efficient than hex - return Buffer.from( + return toBase64( data.slice(SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET, SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE) - ).toString("base64"); + ); } /** @@ -206,3 +204,7 @@ function getSlotFromOffset(data: Uint8Array, offset: number): Slot { // Read only the first 4 bytes of Slot, max value is 4,294,967,295 will be reached 1634 years after genesis return dv.getUint32(offset, true); } + +function toBase64(data: Uint8Array): string { + return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64"); +} diff --git a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts index 1a80d95c1fdc..17692cfcca3a 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts @@ -1,6 +1,4 @@ -import {promisify} from "node:util"; import {describe, it, beforeAll, afterAll, expect} from "vitest"; -import leveldown from "leveldown"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {sleep} from "@lodestar/utils"; import {LevelDbController} from "@lodestar/db"; @@ -38,7 +36,7 @@ describe.skip("eth1 / Eth1Provider", function () { beforeAll(async () => { // Nuke DB to make sure it's empty - await promisify(leveldown.destroy)(dbLocation); + await LevelDbController.destroy(dbLocation); db = new BeaconDb(config, await LevelDbController.create({name: dbLocation}, {logger})); }); @@ -47,7 +45,7 @@ describe.skip("eth1 / Eth1Provider", function () { clearInterval(interval); controller.abort(); await db.close(); - await promisify(leveldown.destroy)(dbLocation); + await LevelDbController.destroy(dbLocation); }); it("Should fetch real Pyrmont eth1 data for block proposing", async function () { diff --git a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts index 976df5d2ae4d..874faea20d14 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts @@ -142,7 +142,7 @@ describe.skip("data serialization through worker boundary", function () { getConnectedPeers: [], getConnectedPeerCount: [], updateStatus: [statusZero], - publishGossip: ["test-topic", bytes, {allowPublishToZeroPeers: true, ignoreDuplicatePublishError: true}], + publishGossip: ["test-topic", bytes, {allowPublishToZeroTopicPeers: true, ignoreDuplicatePublishError: true}], close: [], scrapeMetrics: [], writeProfile: [0, ""], diff --git a/packages/beacon-node/test/perf/util/bytes.test.ts b/packages/beacon-node/test/perf/util/bytes.test.ts index bc3f6cb72e0d..d1d2e968b181 100644 --- a/packages/beacon-node/test/perf/util/bytes.test.ts +++ b/packages/beacon-node/test/perf/util/bytes.test.ts @@ -34,4 +34,40 @@ describe("bytes utils", function () { } }, }); + + itBench({ + id: "Buffer.copy", + fn: () => { + const arr = Buffer.alloc(32 * count); + let offset = 0; + for (const b of buffers) { + b.copy(arr, offset, 0, b.length); + offset += b.length; + } + }, + }); + + itBench({ + id: "Uint8Array.set - with subarray", + fn: () => { + const arr = new Uint8Array(32 * count); + let offset = 0; + for (const b of roots) { + arr.set(b.subarray(0, b.length), offset); + offset += b.length; + } + }, + }); + + itBench({ + id: "Uint8Array.set - without subarray", + fn: () => { + const arr = new Uint8Array(32 * count); + let offset = 0; + for (const b of roots) { + arr.set(b, offset); + offset += b.length; + } + }, + }); }); diff --git a/packages/beacon-node/test/spec/presets/fork_choice.test.ts b/packages/beacon-node/test/spec/presets/fork_choice.test.ts index 49d78cc42f6a..997299c4e0e7 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -27,6 +27,7 @@ import { AttestationImportOpt, BlockSource, BlobSidecarValidation, + BlobsSource, } from "../../../src/chain/blocks/types.js"; import {ZERO_HASH_HEX} from "../../../src/constants/constants.js"; import {PowMergeBlock} from "../../../src/eth1/interface.js"; @@ -209,9 +210,15 @@ const forkChoiceTest = }; }); - blockImport = getBlockInput.postDeneb(config, signedBlock, BlockSource.gossip, blobSidecars, null, [ + blockImport = getBlockInput.postDeneb( + config, + signedBlock, + BlockSource.gossip, + blobSidecars, + BlobsSource.gossip, null, - ]); + [null] + ); } else { blockImport = getBlockInput.preDeneb(config, signedBlock, BlockSource.gossip, null); } @@ -298,6 +305,19 @@ const forkChoiceTest = `Invalid finalized checkpoint at step ${i}` ); } + if (step.checks.get_proposer_head) { + const currentSlot = Math.floor(tickTime / config.SECONDS_PER_SLOT); + const {proposerHead, notReorgedReason} = (chain.forkChoice as ForkChoice).getProposerHead( + head, + tickTime % config.SECONDS_PER_SLOT, + currentSlot + ); + logger.debug(`Not reorged reason ${notReorgedReason} at step ${i}`); + expect(proposerHead.blockRoot).toEqualWithMessage( + step.checks.get_proposer_head, + `Invalid proposer head at step ${i}` + ); + } } // None of the above @@ -458,6 +478,7 @@ type Checks = { justified_checkpoint?: SpecTestCheckpoint; finalized_checkpoint?: SpecTestCheckpoint; proposer_boost_root?: RootHex; + get_proposer_head?: string; }; }; diff --git a/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts b/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts index f614ec10551d..f2c20fd5cbe4 100644 --- a/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts @@ -1,4 +1,4 @@ -import {toHexString} from "@chainsafe/ssz"; +import {BitArray, toHexString} from "@chainsafe/ssz"; import {describe, it} from "vitest"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; @@ -138,6 +138,18 @@ describe("chain / validation / aggregateAndProof", () => { await expectError(chain, signedAggregateAndProof, AttestationErrorCode.AGGREGATOR_NOT_IN_COMMITTEE); }); + it("WRONG_NUMBER_OF_AGGREGATION_BITS", async () => { + const attIndex = 1; + const {chain, signedAggregateAndProof} = getValidData({attIndex}); + const {aggregationBits} = signedAggregateAndProof.message.aggregate; + signedAggregateAndProof.message.aggregate.aggregationBits = new BitArray( + aggregationBits.uint8Array, + aggregationBits.bitLen + 1 + ); + + await expectError(chain, signedAggregateAndProof, AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS); + }); + it("INVALID_SIGNATURE - selection proof sig", async () => { const bitIndex = 1; const {chain, signedAggregateAndProof} = getValidData({bitIndex}); diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index 56fb64104744..1fdedc1dda28 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -3,7 +3,7 @@ import {ssz, deneb} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {beaconBlocksMaybeBlobsByRange} from "../../../src/network/reqresp/index.js"; -import {BlockInputType, BlockSource} from "../../../src/chain/blocks/types.js"; +import {BlockInputType, BlockSource, BlobsSource} from "../../../src/chain/blocks/types.js"; import {initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; import {INetwork} from "../../../src/network/interface.js"; import {ZERO_HASH} from "../../../src/constants/constants.js"; @@ -104,6 +104,7 @@ describe("beaconBlocksMaybeBlobsByRange", () => { block, source: BlockSource.byRange, blobs, + blobsSource: BlobsSource.byRange, blockBytes: null, blobsBytes: blobs.map(() => null), }; diff --git a/packages/beacon-node/test/unit/network/peers/client.test.ts b/packages/beacon-node/test/unit/network/peers/client.test.ts index a179d42157cd..44d16ad4bb8f 100644 --- a/packages/beacon-node/test/unit/network/peers/client.test.ts +++ b/packages/beacon-node/test/unit/network/peers/client.test.ts @@ -28,6 +28,11 @@ describe("clientFromAgentVersion", () => { agentVersion: "js-libp2p/0.32.4", client: ClientKind.Lodestar, }, + { + name: "grandine", + agentVersion: "Grandine/0.4.1-537713d/arm-linux", + client: ClientKind.Grandine, + }, { name: "unknown client", agentVersion: "strange-client-agent-version", diff --git a/packages/beacon-node/vitest.config.ts b/packages/beacon-node/vitest.config.ts index dbf15c3408f0..8e7179d112bd 100644 --- a/packages/beacon-node/vitest.config.ts +++ b/packages/beacon-node/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import {buildTargetPlugin} from "../../scripts/vitest/plugins/buildTargetPlugin.js"; +import {buildTargetPlugin} from "../../scripts/vite/plugins/buildTargetPlugin.js"; import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( diff --git a/packages/beacon-node/vitest.e2e.config.ts b/packages/beacon-node/vitest.e2e.config.ts index 18034e3eedd1..cc2624760c29 100644 --- a/packages/beacon-node/vitest.e2e.config.ts +++ b/packages/beacon-node/vitest.e2e.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import {buildTargetPlugin} from "../../scripts/vitest/plugins/buildTargetPlugin"; +import {buildTargetPlugin} from "../../scripts/vite/plugins/buildTargetPlugin"; import vitestConfig from "../../vitest.base.e2e.config"; export default mergeConfig( diff --git a/packages/beacon-node/vitest.spec.config.ts b/packages/beacon-node/vitest.spec.config.ts index 5a34374d2374..5d957ef16057 100644 --- a/packages/beacon-node/vitest.spec.config.ts +++ b/packages/beacon-node/vitest.spec.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import {buildTargetPlugin} from "../../scripts/vitest/plugins/buildTargetPlugin"; +import {buildTargetPlugin} from "../../scripts/vite/plugins/buildTargetPlugin"; import vitestConfig from "../../vitest.base.spec.config"; export default mergeConfig( diff --git a/packages/cli/README.md b/packages/cli/README.md index 177cb18bc401..028661af856a 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1,7 +1,7 @@ # Command Line Interface for Lodestar [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) ![Node Version](https://img.shields.io/badge/node-12.x-green) diff --git a/packages/cli/package.json b/packages/cli/package.json index cac1b27ee469..6a2f9d04644d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.18.1", + "version": "1.19.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -54,26 +54,26 @@ "@chainsafe/bls": "7.1.3", "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.0.1", - "@chainsafe/blst": "^0.2.10", + "@chainsafe/blst": "^0.2.11", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.7.1", "@chainsafe/ssz": "^0.15.1", "@chainsafe/threads": "^1.11.1", - "@libp2p/crypto": "^3.0.4", - "@libp2p/peer-id": "^4.0.4", - "@libp2p/peer-id-factory": "^4.0.3", - "@lodestar/api": "^1.18.1", - "@lodestar/beacon-node": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/db": "^1.18.1", - "@lodestar/light-client": "^1.18.1", - "@lodestar/logger": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/state-transition": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", - "@lodestar/validator": "^1.18.1", + "@libp2p/crypto": "^4.1.0", + "@libp2p/peer-id": "^4.1.0", + "@libp2p/peer-id-factory": "^4.1.0", + "@lodestar/api": "^1.19.0", + "@lodestar/beacon-node": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/db": "^1.19.0", + "@lodestar/light-client": "^1.19.0", + "@lodestar/logger": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/state-transition": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", + "@lodestar/validator": "^1.19.0", "@multiformats/multiaddr": "^12.1.3", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -89,12 +89,12 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.18.1", + "@lodestar/test-utils": "^1.19.0", "@types/debug": "^4.1.7", "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", "@types/proper-lockfile": "^4.1.4", "@types/yargs": "^17.0.24", - "fastify": "^4.26.2" + "fastify": "^4.27.0" } } diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index a56916cdb232..ec96081d3c75 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import {getHeapStatistics} from "node:v8"; import {Registry} from "prom-client"; import {ErrorAborted} from "@lodestar/utils"; import {LevelDbController} from "@lodestar/db"; @@ -28,6 +29,7 @@ import {initPeerIdAndEnr} from "./initPeerIdAndEnr.js"; const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 15 * 24; const HOURS_TO_MS = 3600 * 1000; +const EIGHT_GB = 8 * 1024 * 1024 * 1024; /** * Runs a beacon node. @@ -35,6 +37,13 @@ const HOURS_TO_MS = 3600 * 1000; export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise { const {config, options, beaconPaths, network, version, commit, peerId, logger} = await beaconHandlerInit(args); + const heapSizeLimit = getHeapStatistics().heap_size_limit; + if (heapSizeLimit < EIGHT_GB) { + logger.warn( + `Node.js heap size limit is too low, consider increasing it to at least ${EIGHT_GB}. See https://chainsafe.github.io/lodestar/faqs#running-a-node for more details.` + ); + } + // initialize directories mkdir(beaconPaths.dataDir); mkdir(beaconPaths.beaconDir); diff --git a/packages/cli/test/scripts/e2e_test_env.ts b/packages/cli/test/scripts/e2e_test_env.ts index 8e564c577f6d..24d0142827a8 100644 --- a/packages/cli/test/scripts/e2e_test_env.ts +++ b/packages/cli/test/scripts/e2e_test_env.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; -import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; -import {connectAllNodes} from "../utils/simulation/utils/network.js"; +import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; +import {connectAllNodes} from "../utils/crucible/utils/network.js"; const altairForkEpoch = 1; const bellatrixForkEpoch = 2; @@ -17,7 +17,7 @@ const {forkConfig} = defineSimTestConfig({ initialNodes: 2, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "e2e-test-env", logsDir: path.join(logFilesDir, "e2e-test-env"), diff --git a/packages/cli/test/sim/backupEthProvider.test.ts b/packages/cli/test/sim/backupEthProvider.test.ts index b44de0afa542..1310119c9c3e 100644 --- a/packages/cli/test/sim/backupEthProvider.test.ts +++ b/packages/cli/test/sim/backupEthProvider.test.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {activePreset} from "@lodestar/params"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {AssertionMatch, BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; -import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/simulation/utils/index.js"; -import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js"; +import {Match, BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; +import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/crucible/utils/index.js"; +import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js"; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; @@ -19,7 +19,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ initialNodes: 3, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "backup-eth-provider", logsDir: path.join(logFilesDir, "backup-eth-provider"), @@ -31,7 +31,7 @@ const env = await SimulationEnvironment.initWithDefaults( env.tracker.register({ ...nodeAssertion, match: ({slot}) => { - return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None; + return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None; }, }); diff --git a/packages/cli/test/sim/deneb.test.ts b/packages/cli/test/sim/deneb.test.ts index 2fc287619976..b9c30a5ff523 100644 --- a/packages/cli/test/sim/deneb.test.ts +++ b/packages/cli/test/sim/deneb.test.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js"; -import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; -import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; -import {createBlobsAssertion} from "../utils/simulation/assertions/blobsAssertion.js"; -import {assertCheckpointSync, assertRangeSync} from "../utils/simulation/utils/syncing.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; +import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js"; +import {createBlobsAssertion} from "../utils/crucible/assertions/blobsAssertion.js"; +import {assertCheckpointSync, assertRangeSync} from "../utils/crucible/utils/syncing.js"; const runTillEpoch = 6; const syncWaitEpoch = 2; @@ -20,7 +20,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ additionalSlotsForTTD: 0, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "deneb", logsDir: path.join(logFilesDir, "deneb"), diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 9fd5371ca01a..b58bece04d9d 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -3,10 +3,10 @@ import path from "node:path"; import assert from "node:assert"; import {toHexString} from "@chainsafe/ssz"; import {ApiError, routes} from "@lodestar/api"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; -import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; -import {waitForSlot} from "../utils/simulation/utils/network.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; +import {waitForSlot} from "../utils/crucible/utils/network.js"; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; @@ -19,7 +19,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ initialNodes: 1, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "beacon-endpoints", logsDir: path.join(logFilesDir, "beacon-endpoints"), diff --git a/packages/cli/test/sim/mixedClient.test.ts b/packages/cli/test/sim/mixedClient.test.ts index 85a7ad0eeea8..bfb2a5a99b1b 100644 --- a/packages/cli/test/sim/mixedClient.test.ts +++ b/packages/cli/test/sim/mixedClient.test.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js"; -import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; -import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js"; +import {Match, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; +import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js"; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; @@ -22,7 +22,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ initialNodes: 2, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "mixed-clients", logsDir: path.join(logFilesDir, "mixed-clients"), @@ -58,7 +58,7 @@ const env = await SimulationEnvironment.initWithDefaults( env.tracker.register({ ...nodeAssertion, match: ({slot}) => { - return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None; + return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None; }, }); diff --git a/packages/cli/test/sim/multiFork.test.ts b/packages/cli/test/sim/multiFork.test.ts index fdedd980e5be..47ad59a165b6 100644 --- a/packages/cli/test/sim/multiFork.test.ts +++ b/packages/cli/test/sim/multiFork.test.ts @@ -1,16 +1,16 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; -import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js"; -import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js"; -import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; -import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; -import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {mergeAssertion} from "../utils/simulation/assertions/mergeAssertion.js"; -import {createForkAssertion} from "../utils/simulation/assertions/forkAssertion.js"; -import {createAccountBalanceAssertion} from "../utils/simulation/assertions/accountBalanceAssertion.js"; -import {createExecutionHeadAssertion} from "../utils/simulation/assertions/executionHeadAssertion.js"; -import {createWithdrawalAssertions} from "../utils/simulation/assertions/withdrawalsAssertion.js"; -import {assertCheckpointSync, assertRangeSync, assertUnknownBlockSync} from "../utils/simulation/utils/syncing.js"; +import {Match, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js"; +import {Simulation} from "../utils/crucible/simulation.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; +import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js"; +import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js"; +import {mergeAssertion} from "../utils/crucible/assertions/mergeAssertion.js"; +import {createForkAssertion} from "../utils/crucible/assertions/forkAssertion.js"; +import {createAccountBalanceAssertion} from "../utils/crucible/assertions/accountBalanceAssertion.js"; +import {createExecutionHeadAssertion} from "../utils/crucible/assertions/executionHeadAssertion.js"; +import {createWithdrawalAssertions} from "../utils/crucible/assertions/withdrawalsAssertion.js"; +import {assertCheckpointSync, assertRangeSync, assertUnknownBlockSync} from "../utils/crucible/utils/syncing.js"; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; @@ -28,7 +28,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ initialNodes: 5, }); -const env = await SimulationEnvironment.initWithDefaults( +const env = await Simulation.initWithDefaults( { id: "multi-fork", logsDir: path.join(logFilesDir, "multi-fork"), @@ -114,7 +114,7 @@ const env = await SimulationEnvironment.initWithDefaults( env.tracker.register({ ...nodeAssertion, match: ({slot}) => { - return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None; + return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None; }, }); @@ -122,9 +122,7 @@ env.tracker.register({ ...mergeAssertion, match: ({slot}) => { // Check at the end of bellatrix fork, merge should happen by then - return slot === env.clock.getLastSlotOfEpoch(bellatrixForkEpoch) - ? AssertionMatch.Assert | AssertionMatch.Remove - : AssertionMatch.None; + return slot === env.clock.getLastSlotOfEpoch(bellatrixForkEpoch) ? Match.Assert | Match.Remove : Match.None; }, }); diff --git a/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts b/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts index 40964a0a7b7d..0f4d0126bb20 100644 --- a/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts +++ b/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts @@ -12,7 +12,7 @@ import {LocalKeystoreDefinition} from "../../../../../src/cmds/validator/keymana const numberOfSigners = 10; describe("keystoreCache", () => { - vi.setConfig({testTimeout: 10000, hookTimeout: 50000}); + vi.setConfig({testTimeout: 20_000, hookTimeout: 50_000}); let definitions: LocalKeystoreDefinition[]; let signers: SignerLocal[]; let secretKeys: Uint8Array[]; diff --git a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts index 0f4173604405..8f1a82a55c3e 100644 --- a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts +++ b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts @@ -10,7 +10,7 @@ import {LocalKeystoreDefinition} from "../../../src/cmds/validator/keymanager/in import {LockfileError, unlockFilepath} from "../../../src/util/lockfile.js"; describe("decryptKeystoreDefinitions", () => { - vi.setConfig({testTimeout: 100_000}); + vi.setConfig({testTimeout: 100_000, hookTimeout: 50_000}); const signal = new AbortController().signal; const dataDir = path.join(testFilesDir, "decrypt-keystores-test"); diff --git a/packages/cli/test/utils/simulation/README.md b/packages/cli/test/utils/crucible/README.md similarity index 98% rename from packages/cli/test/utils/simulation/README.md rename to packages/cli/test/utils/crucible/README.md index b809cfce91fc..a8d8a8e21580 100644 --- a/packages/cli/test/utils/simulation/README.md +++ b/packages/cli/test/utils/crucible/README.md @@ -1,4 +1,6 @@ -# Lodestar Simulation Test +# Crucible by Lodestar + +> a test of faith, patience, or strength Lodestar simulation tests allows to setup a small, local devnet for the variety of Consensus and Execution Layer clients. We use the `minimal` preset for all CL clients. Following clients are currently supported. diff --git a/packages/cli/test/utils/simulation/assertions/accountBalanceAssertion.ts b/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts similarity index 85% rename from packages/cli/test/utils/simulation/assertions/accountBalanceAssertion.ts rename to packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts index 1866d52a8473..e6c4f4c744eb 100644 --- a/packages/cli/test/utils/simulation/assertions/accountBalanceAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts @@ -1,5 +1,5 @@ import {EL_GENESIS_ACCOUNT} from "../constants.js"; -import {AssertionMatch, AssertionResult, NodePair, SimulationAssertion} from "../interfaces.js"; +import {Match, AssertionResult, NodePair, Assertion} from "../interfaces.js"; const transactionAmount = BigInt(2441406250); @@ -13,13 +13,13 @@ export function createAccountBalanceAssertion({ sendTransactionsAtSlot: number[]; validateTotalBalanceAt: number[]; targetNode: NodePair; -}): SimulationAssertion<`accountBalance_${typeof address}`, bigint> { +}): Assertion<`accountBalance_${typeof address}`, bigint> { return { id: `accountBalance_${address}`, match({slot, node}) { - if (sendTransactionsAtSlot.includes(slot) && node.id === targetNode.id) return AssertionMatch.Capture; - if (validateTotalBalanceAt.includes(slot) && node.id === targetNode.id) return AssertionMatch.Assert; - return AssertionMatch.None; + if (sendTransactionsAtSlot.includes(slot) && node.id === targetNode.id) return Match.Capture; + if (validateTotalBalanceAt.includes(slot) && node.id === targetNode.id) return Match.Assert; + return Match.None; }, async capture({node}) { await node.execution.provider?.eth.sendTransaction({ diff --git a/packages/cli/test/utils/simulation/assertions/blobsAssertion.ts b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts similarity index 92% rename from packages/cli/test/utils/simulation/assertions/blobsAssertion.ts rename to packages/cli/test/utils/crucible/assertions/blobsAssertion.ts index e714f0db8d7b..997008272685 100644 --- a/packages/cli/test/utils/simulation/assertions/blobsAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts @@ -1,7 +1,7 @@ import {randomBytes} from "node:crypto"; import {ApiError} from "@lodestar/api"; import {fromHex, toHex} from "@lodestar/utils"; -import {SimulationAssertion, AssertionMatch, AssertionResult, NodePair} from "../interfaces.js"; +import {Assertion, Match, AssertionResult, NodePair} from "../interfaces.js"; import {EL_GENESIS_ACCOUNT, EL_GENESIS_SECRET_KEY, SIM_ENV_CHAIN_ID} from "../constants.js"; import {generateBlobsForTransaction} from "../utils/blobs.js"; import {BlobsEIP4844Transaction} from "../web3js/blobsEIP4844Transaction.js"; @@ -12,16 +12,16 @@ const sentBlobs: Uint8Array[] = []; export function createBlobsAssertion( nodes: NodePair[], {sendBlobsAtSlot, validateBlobsAt}: {sendBlobsAtSlot: number; validateBlobsAt: number} -): SimulationAssertion { +): Assertion { return { id: `blobs-${nodes.map((n) => n.id).join("-")}`, match: ({slot}) => { // Run capture every sendBlobsAtSlot -> validateBlobsAt and validate only at validateBlobsAt return slot === validateBlobsAt - ? AssertionMatch.Capture | AssertionMatch.Assert + ? Match.Capture | Match.Assert : slot >= sendBlobsAtSlot && slot <= validateBlobsAt - ? AssertionMatch.Capture - : AssertionMatch.None; + ? Match.Capture + : Match.None; }, async capture({slot, node}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/attestationCountAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts similarity index 91% rename from packages/cli/test/utils/simulation/assertions/defaults/attestationCountAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts index 9c01a6bdc3ac..5d0f7a268f88 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/attestationCountAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts @@ -1,18 +1,14 @@ import {MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../../interfaces.js"; import {inclusionDelayAssertion, expectedMaxInclusionDelay} from "./inclusionDelayAssertion.js"; export const expectedMinAttestationCount = MAX_COMMITTEES_PER_SLOT - 1; -export const attestationsCountAssertion: SimulationAssertion< - "attestationsCount", - number, - [typeof inclusionDelayAssertion] -> = { +export const attestationsCountAssertion: Assertion<"attestationsCount", number, [typeof inclusionDelayAssertion]> = { id: "attestationsCount", match: () => { // TODO : Disable the assertion for now as the attestations count could be different per slot. - return AssertionMatch.Capture; + return Match.Capture; }, dependencies: [inclusionDelayAssertion], diff --git a/packages/cli/test/utils/simulation/assertions/defaults/attestationParticipationAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts similarity index 92% rename from packages/cli/test/utils/simulation/assertions/defaults/attestationParticipationAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts index 38403f7dc69a..e44cb6cf5629 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/attestationParticipationAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts @@ -2,7 +2,7 @@ import {ApiError} from "@lodestar/api"; import {TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX} from "@lodestar/params"; import {isActiveValidator} from "@lodestar/state-transition"; import {altair} from "@lodestar/types"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../../interfaces.js"; const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX; const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX; @@ -10,7 +10,7 @@ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; const expectedMinParticipationRate = 0.8; -export const attestationParticipationAssertion: SimulationAssertion< +export const attestationParticipationAssertion: Assertion< "attestationParticipation", {head: number; source: number; target: number} > = { @@ -19,10 +19,10 @@ export const attestationParticipationAssertion: SimulationAssertion< // Capture data only when epoch and one extra slot passed // Only assert at first slot of an epoch if (epoch >= forkConfig.ALTAIR_FORK_EPOCH && clock.isFirstSlotOfEpoch(slot)) { - return AssertionMatch.Capture | AssertionMatch.Assert; + return Match.Capture | Match.Assert; } - return AssertionMatch.None; + return Match.None; }, async capture({node, epoch}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/connectedPeerCountAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts similarity index 79% rename from packages/cli/test/utils/simulation/assertions/defaults/connectedPeerCountAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts index 8669938c5254..d3f6fe6038ff 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/connectedPeerCountAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts @@ -1,8 +1,8 @@ import {ApiError} from "@lodestar/api"; -import {AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {AssertionResult, Assertion} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; -export const connectedPeerCountAssertion: SimulationAssertion<"connectedPeerCount", number> = { +export const connectedPeerCountAssertion: Assertion<"connectedPeerCount", number> = { id: "connectedPeerCount", match: everySlotMatcher, async capture({node}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/finalizedAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts similarity index 85% rename from packages/cli/test/utils/simulation/assertions/defaults/finalizedAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts index 4d07e06193d1..44bd01dd865e 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/finalizedAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts @@ -1,9 +1,9 @@ import {ApiError} from "@lodestar/api"; import {Slot} from "@lodestar/types"; -import {AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {AssertionResult, Assertion} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; -export const finalizedAssertion: SimulationAssertion<"finalized", Slot> = { +export const finalizedAssertion: Assertion<"finalized", Slot> = { id: "finalized", match: everySlotMatcher, async capture({node}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/headAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts similarity index 91% rename from packages/cli/test/utils/simulation/assertions/defaults/headAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts index 8d493637d228..9c95b7658144 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/headAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts @@ -1,7 +1,7 @@ import {ApiError} from "@lodestar/api"; import {RootHex, Slot} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; -import {AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {AssertionResult, Assertion} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; export interface HeadSummary { @@ -9,7 +9,7 @@ export interface HeadSummary { slot: Slot; } -export const headAssertion: SimulationAssertion<"head", HeadSummary> = { +export const headAssertion: Assertion<"head", HeadSummary> = { id: "head", match: everySlotMatcher, async capture({node}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/inclusionDelayAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts similarity index 88% rename from packages/cli/test/utils/simulation/assertions/defaults/inclusionDelayAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts index 554df0e31ca9..e3ec467099ba 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/inclusionDelayAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts @@ -1,10 +1,10 @@ -import {AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {AssertionResult, Assertion} from "../../interfaces.js"; import {avg} from "../../utils/index.js"; import {everySlotMatcher} from "../matchers.js"; export const expectedMaxInclusionDelay = 2; -export const inclusionDelayAssertion: SimulationAssertion<"inclusionDelay", number> = { +export const inclusionDelayAssertion: Assertion<"inclusionDelay", number> = { id: "inclusionDelay", match: everySlotMatcher, async capture(input) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/index.ts b/packages/cli/test/utils/crucible/assertions/defaults/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/assertions/defaults/index.ts rename to packages/cli/test/utils/crucible/assertions/defaults/index.ts diff --git a/packages/cli/test/utils/simulation/assertions/defaults/missedBlocksAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts similarity index 82% rename from packages/cli/test/utils/simulation/assertions/defaults/missedBlocksAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts index 299280a37c7d..1209a6469ca3 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/missedBlocksAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts @@ -1,12 +1,12 @@ import {isNullish} from "../../../../utils.js"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../../interfaces.js"; import {arrayEquals} from "../../utils/index.js"; import {headAssertion} from "./headAssertion.js"; -export const missedBlocksAssertion: SimulationAssertion<"missedBlocks", number[], [typeof headAssertion]> = { +export const missedBlocksAssertion: Assertion<"missedBlocks", number[], [typeof headAssertion]> = { id: "missedBlocks", match: ({clock, slot}) => { - return clock.isLastSlotOfEpoch(slot) ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.None; + return clock.isLastSlotOfEpoch(slot) ? Match.Capture | Match.Assert : Match.None; }, dependencies: [headAssertion], async capture({node, epoch, slot, dependantStores, clock}) { diff --git a/packages/cli/test/utils/simulation/assertions/defaults/syncCommitteeParticipationAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts similarity index 85% rename from packages/cli/test/utils/simulation/assertions/defaults/syncCommitteeParticipationAssertion.ts rename to packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts index 5cce7554d737..83b945da0b0a 100644 --- a/packages/cli/test/utils/simulation/assertions/defaults/syncCommitteeParticipationAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts @@ -1,18 +1,18 @@ import {ForkName} from "@lodestar/params"; import {altair} from "@lodestar/types"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../../interfaces.js"; import {avg} from "../../utils/index.js"; // Until we identity and fix the following issue, reducing the expected sync committee participation rate from 0.9 to 0.75 // https://github.com/ChainSafe/lodestar/issues/6432 export const expectedMinSyncParticipationRate = 0.75; -export const syncCommitteeParticipationAssertion: SimulationAssertion<"syncCommitteeParticipation", number> = { +export const syncCommitteeParticipationAssertion: Assertion<"syncCommitteeParticipation", number> = { id: "syncCommitteeParticipation", match: ({slot, clock, fork}) => { - if (fork === ForkName.phase0) return AssertionMatch.None; + if (fork === ForkName.phase0) return Match.None; - return clock.isLastSlotOfEpoch(slot) ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.Capture; + return clock.isLastSlotOfEpoch(slot) ? Match.Capture | Match.Assert : Match.Capture; }, async capture({block}) { diff --git a/packages/cli/test/utils/simulation/assertions/executionHeadAssertion.ts b/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts similarity index 86% rename from packages/cli/test/utils/simulation/assertions/executionHeadAssertion.ts rename to packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts index cef08bb38246..391fb27e6584 100644 --- a/packages/cli/test/utils/simulation/assertions/executionHeadAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts @@ -1,21 +1,21 @@ import {ApiError} from "@lodestar/api"; import {toHex} from "@lodestar/utils"; import {bellatrix} from "@lodestar/types"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../interfaces.js"; export function createExecutionHeadAssertion({ checkForSlot, }: { checkForSlot: number[]; -}): SimulationAssertion< +}): Assertion< "executionHead", {executionHead: {hash: string}; consensusHead: {executionPayload: {blockHash: string}}} > { return { id: "executionHead", match({slot}) { - if (checkForSlot.includes(slot)) return AssertionMatch.Capture | AssertionMatch.Assert; - return AssertionMatch.None; + if (checkForSlot.includes(slot)) return Match.Capture | Match.Assert; + return Match.None; }, async capture({node}) { const blockNumber = await node.execution.provider?.eth.getBlockNumber(); diff --git a/packages/cli/test/utils/simulation/assertions/forkAssertion.ts b/packages/cli/test/utils/crucible/assertions/forkAssertion.ts similarity index 82% rename from packages/cli/test/utils/simulation/assertions/forkAssertion.ts rename to packages/cli/test/utils/crucible/assertions/forkAssertion.ts index c78a617efce0..5dc804c642f1 100644 --- a/packages/cli/test/utils/simulation/assertions/forkAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/forkAssertion.ts @@ -2,15 +2,15 @@ import {ApiError} from "@lodestar/api"; import {ForkName} from "@lodestar/params"; import {Epoch} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../interfaces.js"; -export function createForkAssertion(fork: ForkName, epoch: Epoch): SimulationAssertion { +export function createForkAssertion(fork: ForkName, epoch: Epoch): Assertion { return { id: `fork-${fork}`, match: ({slot, clock}) => { return clock.isFirstSlotOfEpoch(slot) && epoch === clock.getEpochForSlot(slot) - ? AssertionMatch.Assert | AssertionMatch.Remove - : AssertionMatch.None; + ? Match.Assert | Match.Remove + : Match.None; }, assert: async ({node, slot, forkConfig}) => { const errors: AssertionResult[] = []; diff --git a/packages/cli/test/utils/simulation/assertions/lighthousePeerScoreAssertion.ts b/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts similarity index 91% rename from packages/cli/test/utils/simulation/assertions/lighthousePeerScoreAssertion.ts rename to packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts index d7b5e4d6c087..1b6837a881e3 100644 --- a/packages/cli/test/utils/simulation/assertions/lighthousePeerScoreAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts @@ -1,12 +1,12 @@ import {ApiError} from "@lodestar/api"; -import {AssertionResult, BeaconClient, LighthouseAPI, NodePair, SimulationAssertion} from "../interfaces.js"; +import {AssertionResult, BeaconClient, LighthouseAPI, NodePair, Assertion} from "../interfaces.js"; import {neverMatcher} from "./matchers.js"; const MIN_GOSSIPSUB_SCORE = 10; let peersIdMapCache: Record; -export const lighthousePeerScoreAssertion: SimulationAssertion<"lighthousePeerScore", {gossipsubScore: number}> = { +export const lighthousePeerScoreAssertion: Assertion<"lighthousePeerScore", {gossipsubScore: number}> = { id: "lighthousePeerScore", match: neverMatcher, async assert({nodes, node}) { diff --git a/packages/cli/test/utils/crucible/assertions/matchers.ts b/packages/cli/test/utils/crucible/assertions/matchers.ts new file mode 100644 index 000000000000..bc51f3fb76ad --- /dev/null +++ b/packages/cli/test/utils/crucible/assertions/matchers.ts @@ -0,0 +1,15 @@ +import {Match, Matcher} from "../interfaces.js"; + +export const everySlotMatcher: Matcher = ({slot}) => (slot >= 0 ? Match.Capture | Match.Assert : Match.None); + +export const everyEpochMatcher: Matcher = ({slot, clock}) => + clock.isLastSlotOfEpoch(slot) ? Match.Capture | Match.Assert : Match.Capture; + +export const neverMatcher: Matcher = () => Match.None; + +export const onceOnSlotMatcher = + (userSlot: number): Matcher => + ({slot}) => + slot === userSlot ? Match.Capture | Match.Assert : Match.None; + +export const onceOnStartupMatcher = onceOnSlotMatcher(1); diff --git a/packages/cli/test/utils/simulation/assertions/mergeAssertion.ts b/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts similarity index 83% rename from packages/cli/test/utils/simulation/assertions/mergeAssertion.ts rename to packages/cli/test/utils/crucible/assertions/mergeAssertion.ts index a7b522504dfc..d7a90857ae2c 100644 --- a/packages/cli/test/utils/simulation/assertions/mergeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts @@ -1,9 +1,9 @@ import {ApiError} from "@lodestar/api"; import {BeaconStateAllForks, isExecutionStateType, isMergeTransitionComplete} from "@lodestar/state-transition"; -import {AssertionResult, SimulationAssertion} from "../interfaces.js"; +import {AssertionResult, Assertion} from "../interfaces.js"; import {neverMatcher} from "./matchers.js"; -export const mergeAssertion: SimulationAssertion<"merge", string> = { +export const mergeAssertion: Assertion<"merge", string> = { id: "merge", // Include into particular test with custom condition match: neverMatcher, diff --git a/packages/cli/test/utils/simulation/assertions/nodeAssertion.ts b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts similarity index 90% rename from packages/cli/test/utils/simulation/assertions/nodeAssertion.ts rename to packages/cli/test/utils/crucible/assertions/nodeAssertion.ts index 25784b688d46..7a449b3f669f 100644 --- a/packages/cli/test/utils/simulation/assertions/nodeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts @@ -1,11 +1,11 @@ import type {SecretKey} from "@chainsafe/bls/types"; import {routes} from "@lodestar/api/beacon"; import {ApiError} from "@lodestar/api"; -import {AssertionResult, ValidatorClientKeys, SimulationAssertion, ValidatorClient} from "../interfaces.js"; +import {AssertionResult, ValidatorClientKeys, Assertion, ValidatorClient} from "../interfaces.js"; import {arrayEquals} from "../utils/index.js"; import {neverMatcher} from "./matchers.js"; -export const nodeAssertion: SimulationAssertion<"node", {health: number; keyManagerKeys: string[]}> = { +export const nodeAssertion: Assertion<"node", {health: number; keyManagerKeys: string[]}> = { id: "node", // Include into particular test with custom condition match: neverMatcher, diff --git a/packages/cli/test/utils/simulation/assertions/withdrawalsAssertion.ts b/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts similarity index 93% rename from packages/cli/test/utils/simulation/assertions/withdrawalsAssertion.ts rename to packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts index 6f7be91bf3c7..7daa38682829 100644 --- a/packages/cli/test/utils/simulation/assertions/withdrawalsAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts @@ -1,7 +1,7 @@ import {capella} from "@lodestar/types"; import {ApiError} from "@lodestar/api"; import {MAX_WITHDRAWALS_PER_PAYLOAD} from "@lodestar/params"; -import {AssertionMatch, AssertionResult, SimulationAssertion} from "../interfaces.js"; +import {Match, AssertionResult, Assertion} from "../interfaces.js"; type WithdrawalsData = { withdrawalCount: number; @@ -11,14 +11,13 @@ type WithdrawalsData = { export function createWithdrawalAssertions( nodeId: T -): SimulationAssertion<`withdrawals_${T}`, WithdrawalsData> { +): Assertion<`withdrawals_${T}`, WithdrawalsData> { return { id: `withdrawals_${nodeId}`, match({forkConfig, epoch, node}) { - if (nodeId === node.id && epoch === forkConfig.CAPELLA_FORK_EPOCH) - return AssertionMatch.Capture | AssertionMatch.Assert; + if (nodeId === node.id && epoch === forkConfig.CAPELLA_FORK_EPOCH) return Match.Capture | Match.Assert; - return AssertionMatch.None; + return Match.None; }, async capture({block, node, slot}) { const withdrawals = (block as capella.SignedBeaconBlock).message.body.executionPayload.withdrawals; diff --git a/packages/cli/test/utils/simulation/clients/beacon/index.ts b/packages/cli/test/utils/crucible/clients/beacon/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/beacon/index.ts rename to packages/cli/test/utils/crucible/clients/beacon/index.ts diff --git a/packages/cli/test/utils/simulation/clients/beacon/lighthouse.ts b/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/beacon/lighthouse.ts rename to packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts diff --git a/packages/cli/test/utils/simulation/clients/beacon/lodestar.ts b/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/beacon/lodestar.ts rename to packages/cli/test/utils/crucible/clients/beacon/lodestar.ts diff --git a/packages/cli/test/utils/simulation/clients/execution/geth.ts b/packages/cli/test/utils/crucible/clients/execution/geth.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/execution/geth.ts rename to packages/cli/test/utils/crucible/clients/execution/geth.ts diff --git a/packages/cli/test/utils/simulation/clients/execution/index.ts b/packages/cli/test/utils/crucible/clients/execution/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/execution/index.ts rename to packages/cli/test/utils/crucible/clients/execution/index.ts diff --git a/packages/cli/test/utils/simulation/clients/execution/mock.ts b/packages/cli/test/utils/crucible/clients/execution/mock.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/execution/mock.ts rename to packages/cli/test/utils/crucible/clients/execution/mock.ts diff --git a/packages/cli/test/utils/simulation/clients/execution/nethermind.ts b/packages/cli/test/utils/crucible/clients/execution/nethermind.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/execution/nethermind.ts rename to packages/cli/test/utils/crucible/clients/execution/nethermind.ts diff --git a/packages/cli/test/utils/simulation/clients/validator/index.ts b/packages/cli/test/utils/crucible/clients/validator/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/validator/index.ts rename to packages/cli/test/utils/crucible/clients/validator/index.ts diff --git a/packages/cli/test/utils/simulation/clients/validator/lighthouse.ts b/packages/cli/test/utils/crucible/clients/validator/lighthouse.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/validator/lighthouse.ts rename to packages/cli/test/utils/crucible/clients/validator/lighthouse.ts diff --git a/packages/cli/test/utils/simulation/clients/validator/lodestar.ts b/packages/cli/test/utils/crucible/clients/validator/lodestar.ts similarity index 100% rename from packages/cli/test/utils/simulation/clients/validator/lodestar.ts rename to packages/cli/test/utils/crucible/clients/validator/lodestar.ts diff --git a/packages/cli/test/utils/simulation/constants.ts b/packages/cli/test/utils/crucible/constants.ts similarity index 100% rename from packages/cli/test/utils/simulation/constants.ts rename to packages/cli/test/utils/crucible/constants.ts diff --git a/packages/cli/test/utils/simulation/epochClock.ts b/packages/cli/test/utils/crucible/epochClock.ts similarity index 100% rename from packages/cli/test/utils/simulation/epochClock.ts rename to packages/cli/test/utils/crucible/epochClock.ts diff --git a/packages/cli/test/utils/simulation/externalSignerServer.ts b/packages/cli/test/utils/crucible/externalSignerServer.ts similarity index 100% rename from packages/cli/test/utils/simulation/externalSignerServer.ts rename to packages/cli/test/utils/crucible/externalSignerServer.ts diff --git a/packages/cli/test/utils/simulation/interfaces.ts b/packages/cli/test/utils/crucible/interfaces.ts similarity index 88% rename from packages/cli/test/utils/simulation/interfaces.ts rename to packages/cli/test/utils/crucible/interfaces.ts index 4fd9c0065c4b..a7934f962d4b 100644 --- a/packages/cli/test/utils/simulation/interfaces.ts +++ b/packages/cli/test/utils/crucible/interfaces.ts @@ -317,24 +317,23 @@ export interface AssertionInput { node: NodePair; } -export interface SimulationCaptureInput> extends AssertionInput { +export interface CaptureInput> extends AssertionInput { block: allForks.SignedBeaconBlock; dependantStores: D; } -export interface SimulationAssertionInput = Record> - extends AssertionInput { +export interface AssertInput = Record> extends AssertionInput { nodes: NodePair[]; store: Record; dependantStores: D; } -export interface SimulationDumpInput extends Omit { +export interface DumpInput extends Omit { nodes: NodePair[]; store: Record>; } -export type SimulationMatcherInput = AssertionInput; +export type MatcherInput = AssertionInput; /** * Bitwise flag to indicate what to do with the assertion @@ -345,45 +344,42 @@ export type SimulationMatcherInput = AssertionInput; * @example * Capture and assert: `AssertionMatch.Capture | AssertionMatch.Assert` */ -export enum AssertionMatch { +export enum Match { None = 0, Capture = 1 << 0, Assert = 1 << 1, Remove = 1 << 2, } -export type AssertionMatcher = (input: SimulationMatcherInput) => AssertionMatch; -export type ExtractAssertionType = - T extends SimulationAssertion ? (A extends I ? B : never) : never; -export type ExtractAssertionId = T extends SimulationAssertion ? A : never; +export type Matcher = (input: MatcherInput) => Match; +export type ExtractAssertionType = T extends Assertion ? (A extends I ? B : never) : never; +export type ExtractAssertionId = T extends Assertion ? A : never; export type StoreType = Record< AssertionId, Record> >; -export type StoreTypes> = { +export type StoreTypes> = { [Id in IDs]: Record | undefined>>; }; -export interface SimulationAssertion< +export interface Assertion< IdType extends string = string, ValueType = unknown, - Dependencies extends SimulationAssertion[] = SimulationAssertion[], + Dependencies extends Assertion[] = Assertion[], > { readonly id: IdType; - capture?( - input: SimulationCaptureInput & StoreType> - ): Promise; - match: AssertionMatcher; + capture?(input: CaptureInput & StoreType>): Promise; + match: Matcher; assert( - input: SimulationAssertionInput & StoreType> + input: AssertInput & StoreType> ): Promise; dependencies?: Dependencies; // Use to dump the data to CSV files, as each assertion implementation knows // how to make the dump more readable, so we define it in assertion // Return object as key-value pair for file name as dump data - dump?(input: SimulationDumpInput): Promise>; + dump?(input: DumpInput): Promise>; } export type AssertionResult = string | [string, Record]; -export interface SimulationAssertionError { +export interface AssertionError { slot: Slot; epoch: Epoch; assertionId: string; @@ -402,14 +398,14 @@ export type Eth1GenesisBlock = { alloc: Record; }; -export abstract class SimulationReporter { +export abstract class SimulationReporter { constructor( protected options: { clock: EpochClock; forkConfig: ChainForkConfig; stores: StoreTypes; nodes: NodePair[]; - errors: SimulationAssertionError[]; + errors: AssertionError[]; logger: Logger; } ) {} diff --git a/packages/cli/test/utils/simulation/runner/childProcessRunner.ts b/packages/cli/test/utils/crucible/runner/childProcessRunner.ts similarity index 100% rename from packages/cli/test/utils/simulation/runner/childProcessRunner.ts rename to packages/cli/test/utils/crucible/runner/childProcessRunner.ts diff --git a/packages/cli/test/utils/simulation/runner/dockerRunner.ts b/packages/cli/test/utils/crucible/runner/dockerRunner.ts similarity index 100% rename from packages/cli/test/utils/simulation/runner/dockerRunner.ts rename to packages/cli/test/utils/crucible/runner/dockerRunner.ts diff --git a/packages/cli/test/utils/simulation/runner/index.ts b/packages/cli/test/utils/crucible/runner/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/runner/index.ts rename to packages/cli/test/utils/crucible/runner/index.ts diff --git a/packages/cli/test/utils/simulation/simulationEnvironment.ts b/packages/cli/test/utils/crucible/simulation.ts similarity index 98% rename from packages/cli/test/utils/simulation/simulationEnvironment.ts rename to packages/cli/test/utils/crucible/simulation.ts index 7b62870f806a..7a2343b6082d 100644 --- a/packages/cli/test/utils/simulation/simulationEnvironment.ts +++ b/packages/cli/test/utils/crucible/simulation.ts @@ -38,7 +38,7 @@ interface StartOpts { runTimeoutMs: number; } -export class SimulationEnvironment { +export class Simulation { readonly nodes: NodePair[] = []; readonly clock: EpochClock; readonly tracker: SimulationTracker; @@ -75,7 +75,7 @@ export class SimulationEnvironment { this.externalSigner = new ExternalSignerServer([]); this.runner = new Runner({logsDir: this.options.logsDir, logger: this.logger.child({module: "runner"})}); - this.tracker = SimulationTracker.initWithDefaultAssertions({ + this.tracker = SimulationTracker.initWithDefaults({ logsDir: options.logsDir, logger: this.logger, nodes: [], @@ -88,8 +88,8 @@ export class SimulationEnvironment { static async initWithDefaults( {forkConfig, logsDir, id, trustedSetup}: SimulationInitOptions, clients: NodePairDefinition[] - ): Promise { - const env = new SimulationEnvironment(forkConfig, { + ): Promise { + const env = new Simulation(forkConfig, { logsDir, id, genesisTime: Math.floor(Date.now() / 1000), diff --git a/packages/cli/test/utils/simulation/simulationTracker.ts b/packages/cli/test/utils/crucible/simulationTracker.ts similarity index 94% rename from packages/cli/test/utils/simulation/simulationTracker.ts rename to packages/cli/test/utils/crucible/simulationTracker.ts index 909f92ede8ea..3533015d58d5 100644 --- a/packages/cli/test/utils/simulation/simulationTracker.ts +++ b/packages/cli/test/utils/crucible/simulationTracker.ts @@ -9,12 +9,12 @@ import {LoggerNode} from "@lodestar/logger/node"; import {isNullish} from "../../utils.js"; import {EpochClock} from "./epochClock.js"; import { - AssertionMatch, + Match, AtLeast, NodeId, NodePair, - SimulationAssertion, - SimulationAssertionError, + Assertion, + AssertionError, SimulationReporter, StoreType, StoreTypes, @@ -54,10 +54,7 @@ const eventStreamEventMap = { type Stores = StoreTypes & StoreType; -export function getStoresForAssertions( - stores: Stores, - dependencies: D -): StoreTypes { +export function getStoresForAssertions(stores: Stores, dependencies: D): StoreTypes { const filterStores: Record = {}; for (const assertion of dependencies) { @@ -90,9 +87,9 @@ export class SimulationTracker { private forkConfig: ChainForkConfig; private running = false; - private errors: SimulationAssertionError[] = []; + private errors: AssertionError[] = []; private stores: Stores; - private assertions: SimulationAssertion[]; + private assertions: Assertion[]; private assertionIdsMap: Record = {}; private constructor({signal, nodes, clock, config, logger, logsDir}: SimulationTrackerInitOptions) { this.signal = signal; @@ -103,7 +100,7 @@ export class SimulationTracker { this.logger = logger.child({module: "tracker"}); this.stores = {} as StoreTypes & StoreType; - this.assertions = [] as SimulationAssertion[]; + this.assertions = [] as Assertion[]; this.reporter = new TableReporter({ logger: this.logger.child({module: "reporter"}), clock: this.clock, @@ -114,7 +111,7 @@ export class SimulationTracker { }); } - static initWithDefaultAssertions(opts: SimulationTrackerInitOptions): SimulationTracker { + static initWithDefaults(opts: SimulationTrackerInitOptions): SimulationTracker { const tracker = new SimulationTracker(opts); for (const assertion of defaultAssertions) { @@ -230,7 +227,7 @@ export class SimulationTracker { this.emitter.once(`${node.beacon.id}:slot:${slot}`, cb); } - register(assertion: SimulationAssertion): void { + register(assertion: Assertion): void { if (assertion.id in this.assertionIdsMap) { throw new Error(`The assertion "${assertion.id}" is already registered`); } @@ -250,7 +247,7 @@ export class SimulationTracker { } } - record(error: AtLeast): void { + record(error: AtLeast): void { this.errors.push({ ...error, epoch: error.epoch ?? this.clock.getEpochForSlot(error.slot), @@ -336,7 +333,7 @@ export class SimulationTracker { fork: this.forkConfig.getForkName(slot), }); - if (match & AssertionMatch.None || !(match & AssertionMatch.Capture)) continue; + if (match & Match.None || !(match & Match.Capture)) continue; if (!assertion.capture) { throw new Error(`Assertion "${assertion.id}" has no capture function`); @@ -383,7 +380,7 @@ export class SimulationTracker { fork: this.forkConfig.getForkName(slot), }); - if (match & AssertionMatch.None || !(match & AssertionMatch.Assert)) continue; + if (match & Match.None || !(match & Match.Assert)) continue; try { const errors = await assertion.assert({ diff --git a/packages/cli/test/utils/simulation/tableRenderer.ts b/packages/cli/test/utils/crucible/tableRenderer.ts similarity index 100% rename from packages/cli/test/utils/simulation/tableRenderer.ts rename to packages/cli/test/utils/crucible/tableRenderer.ts diff --git a/packages/cli/test/utils/simulation/tableReporter.ts b/packages/cli/test/utils/crucible/tableReporter.ts similarity index 100% rename from packages/cli/test/utils/simulation/tableReporter.ts rename to packages/cli/test/utils/crucible/tableReporter.ts diff --git a/packages/cli/test/utils/simulation/utils/blobs.ts b/packages/cli/test/utils/crucible/utils/blobs.ts similarity index 100% rename from packages/cli/test/utils/simulation/utils/blobs.ts rename to packages/cli/test/utils/crucible/utils/blobs.ts diff --git a/packages/cli/test/utils/simulation/utils/executionGenesis.ts b/packages/cli/test/utils/crucible/utils/executionGenesis.ts similarity index 100% rename from packages/cli/test/utils/simulation/utils/executionGenesis.ts rename to packages/cli/test/utils/crucible/utils/executionGenesis.ts diff --git a/packages/cli/test/utils/simulation/utils/index.ts b/packages/cli/test/utils/crucible/utils/index.ts similarity index 97% rename from packages/cli/test/utils/simulation/utils/index.ts rename to packages/cli/test/utils/crucible/utils/index.ts index 20fc6d6fbd08..0b6ae1bba1e5 100644 --- a/packages/cli/test/utils/simulation/utils/index.ts +++ b/packages/cli/test/utils/crucible/utils/index.ts @@ -9,7 +9,7 @@ import { SIM_ENV_NETWORK_ID, SIM_TESTS_SECONDS_PER_SLOT, } from "../constants.js"; -import {SimulationEnvironment} from "../simulationEnvironment.js"; +import {Simulation} from "../simulation.js"; export const logFilesDir = "test-logs"; @@ -174,7 +174,7 @@ export const replaceIpFromUrl = (url: string, ip: string): string => url.replace export const makeUniqueArray = (arr: T[]): T[] => [...new Set(arr)]; -export const registerProcessHandler = (env: SimulationEnvironment): void => { +export const registerProcessHandler = (env: Simulation): void => { process.on("unhandledRejection", async (reason, promise) => { console.error("Unhandled Rejection at:", promise, "reason:", reason); await env.stop(1, "Unhandled promise rejection"); diff --git a/packages/cli/test/utils/simulation/utils/keys.ts b/packages/cli/test/utils/crucible/utils/keys.ts similarity index 100% rename from packages/cli/test/utils/simulation/utils/keys.ts rename to packages/cli/test/utils/crucible/utils/keys.ts diff --git a/packages/cli/test/utils/simulation/utils/network.ts b/packages/cli/test/utils/crucible/utils/network.ts similarity index 94% rename from packages/cli/test/utils/simulation/utils/network.ts rename to packages/cli/test/utils/crucible/utils/network.ts index fc62d0d6d886..b78087d8f931 100644 --- a/packages/cli/test/utils/simulation/utils/network.ts +++ b/packages/cli/test/utils/crucible/utils/network.ts @@ -3,7 +3,7 @@ import {ApiError} from "@lodestar/api"; import {Slot, allForks} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; import {BeaconClient, BeaconNode, ExecutionClient, ExecutionNode, NodePair} from "../interfaces.js"; -import {SimulationEnvironment} from "../simulationEnvironment.js"; +import {Simulation} from "../simulation.js"; import {SimulationTrackerEvent} from "../simulationTracker.js"; export async function connectAllNodes(nodes: NodePair[]): Promise { @@ -61,7 +61,7 @@ export async function connectNewELNode(newNode: ExecutionNode, nodes: ExecutionN } export async function waitForNodeSync( - env: SimulationEnvironment, + env: Simulation, node: NodePair, options?: {head: string; slot: Slot} ): Promise { @@ -73,7 +73,7 @@ export async function waitForNodeSync( return waitForNodeSyncStatus(env, node); } -export async function waitForNodeSyncStatus(env: SimulationEnvironment, node: NodePair): Promise { +export async function waitForNodeSyncStatus(env: Simulation, node: NodePair): Promise { // eslint-disable-next-line no-constant-condition while (true) { const result = await node.beacon.api.node.getSyncingStatus(); @@ -87,7 +87,7 @@ export async function waitForNodeSyncStatus(env: SimulationEnvironment, node: No } export async function waitForHead( - env: SimulationEnvironment, + env: Simulation, node: NodePair, options: {slot: Slot; head: string; silent?: boolean} ): Promise { @@ -122,7 +122,7 @@ export async function waitForHead( export async function waitForSlot( message: string, - {env, slot, nodes}: {env: SimulationEnvironment; slot: Slot; nodes?: NodePair[]} + {env, slot, nodes}: {env: Simulation; slot: Slot; nodes?: NodePair[]} ): Promise { nodes = nodes ?? env.nodes; diff --git a/packages/cli/test/utils/simulation/utils/paths.ts b/packages/cli/test/utils/crucible/utils/paths.ts similarity index 100% rename from packages/cli/test/utils/simulation/utils/paths.ts rename to packages/cli/test/utils/crucible/utils/paths.ts diff --git a/packages/cli/test/utils/simulation/utils/ports.ts b/packages/cli/test/utils/crucible/utils/ports.ts similarity index 100% rename from packages/cli/test/utils/simulation/utils/ports.ts rename to packages/cli/test/utils/crucible/utils/ports.ts diff --git a/packages/cli/test/utils/simulation/utils/syncing.ts b/packages/cli/test/utils/crucible/utils/syncing.ts similarity index 93% rename from packages/cli/test/utils/simulation/utils/syncing.ts rename to packages/cli/test/utils/crucible/utils/syncing.ts index fdfe3785e623..d56f7d7bb388 100644 --- a/packages/cli/test/utils/simulation/utils/syncing.ts +++ b/packages/cli/test/utils/crucible/utils/syncing.ts @@ -1,11 +1,11 @@ import {ApiError, routes} from "@lodestar/api"; import {Slot} from "@lodestar/types"; import {sleep, toHex} from "@lodestar/utils"; -import type {SimulationEnvironment} from "../simulationEnvironment.js"; +import type {Simulation} from "../simulation.js"; import {BeaconClient, ExecutionClient, NodePair} from "../interfaces.js"; import {connectNewCLNode, connectNewELNode, connectNewNode, waitForHead, waitForSlot} from "./network.js"; -export async function assertRangeSync(env: SimulationEnvironment): Promise { +export async function assertRangeSync(env: Simulation): Promise { const currentHead = await env.nodes[0].beacon.api.beacon.getBlockHeader("head"); ApiError.assert(currentHead); @@ -53,7 +53,7 @@ export async function assertRangeSync(env: SimulationEnvironment): Promise await rangeSync.execution.job.stop(); } -export async function assertCheckpointSync(env: SimulationEnvironment): Promise { +export async function assertCheckpointSync(env: Simulation): Promise { if (env.clock.currentEpoch <= 4) { // First checkpoint finalized is at least 4 epochs await waitForSlot("Waiting for 4th epoch to pass, to get first finalized checkpoint", { @@ -93,7 +93,7 @@ export async function assertCheckpointSync(env: SimulationEnvironment): Promise< await checkpointSync.execution.job.stop(); } -export async function assertUnknownBlockSync(env: SimulationEnvironment): Promise { +export async function assertUnknownBlockSync(env: Simulation): Promise { const currentHead = await env.nodes[0].beacon.api.beacon.getBlockV2("head"); ApiError.assert(currentHead); const currentSidecars = await env.nodes[0].beacon.api.beacon.getBlobSidecars(currentHead.response.data.message.slot); @@ -170,7 +170,7 @@ export async function assertUnknownBlockSync(env: SimulationEnvironment): Promis } export async function waitForNodeSync( - env: SimulationEnvironment, + env: Simulation, node: NodePair, options?: {head: string; slot: Slot} ): Promise { @@ -182,7 +182,7 @@ export async function waitForNodeSync( return waitForNodeSyncStatus(env, node); } -export async function waitForNodeSyncStatus(env: SimulationEnvironment, node: NodePair): Promise { +export async function waitForNodeSyncStatus(env: Simulation, node: NodePair): Promise { // eslint-disable-next-line no-constant-condition while (true) { const result = await node.beacon.api.node.getSyncingStatus(); diff --git a/packages/cli/test/utils/simulation/web3js/blobsEIP4844Transaction.ts b/packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts similarity index 100% rename from packages/cli/test/utils/simulation/web3js/blobsEIP4844Transaction.ts rename to packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts diff --git a/packages/cli/test/utils/simulation/web3js/plugins/index.ts b/packages/cli/test/utils/crucible/web3js/plugins/index.ts similarity index 100% rename from packages/cli/test/utils/simulation/web3js/plugins/index.ts rename to packages/cli/test/utils/crucible/web3js/plugins/index.ts diff --git a/packages/cli/test/utils/simulation/web3js/plugins/web3AdminPlugin.ts b/packages/cli/test/utils/crucible/web3js/plugins/web3AdminPlugin.ts similarity index 100% rename from packages/cli/test/utils/simulation/web3js/plugins/web3AdminPlugin.ts rename to packages/cli/test/utils/crucible/web3js/plugins/web3AdminPlugin.ts diff --git a/packages/cli/test/utils/simulation/web3js/plugins/web3ExtendedEthPlugin.ts b/packages/cli/test/utils/crucible/web3js/plugins/web3ExtendedEthPlugin.ts similarity index 100% rename from packages/cli/test/utils/simulation/web3js/plugins/web3ExtendedEthPlugin.ts rename to packages/cli/test/utils/crucible/web3js/plugins/web3ExtendedEthPlugin.ts diff --git a/packages/cli/test/utils/simulation/assertions/matchers.ts b/packages/cli/test/utils/simulation/assertions/matchers.ts deleted file mode 100644 index 931157e49e1f..000000000000 --- a/packages/cli/test/utils/simulation/assertions/matchers.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {AssertionMatch, AssertionMatcher} from "../interfaces.js"; - -export const everySlotMatcher: AssertionMatcher = ({slot}) => - slot >= 0 ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.None; - -export const everyEpochMatcher: AssertionMatcher = ({slot, clock}) => - clock.isLastSlotOfEpoch(slot) ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.Capture; - -export const neverMatcher: AssertionMatcher = () => AssertionMatch.None; - -export const onceOnSlotMatcher = - (userSlot: number): AssertionMatcher => - ({slot}) => - slot === userSlot ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.None; - -export const onceOnStartupMatcher = onceOnSlotMatcher(1); diff --git a/packages/config/README.md b/packages/config/README.md index 430a67e7e19b..46ce14bac5dc 100644 --- a/packages/config/README.md +++ b/packages/config/README.md @@ -2,7 +2,7 @@ [![npm](https://img.shields.io/npm/v/@lodestar/config)](https://www.npmjs.com/package/@lodestar/config) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) ![Node Version](https://img.shields.io/badge/node-12.x-green) diff --git a/packages/config/package.json b/packages/config/package.json index 71463b6b5caf..bc8f880cb7a8 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.18.1", + "version": "1.19.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,7 +65,7 @@ ], "dependencies": { "@chainsafe/ssz": "^0.15.1", - "@lodestar/params": "^1.18.1", - "@lodestar/types": "^1.18.1" + "@lodestar/params": "^1.19.0", + "@lodestar/types": "^1.19.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index 3ca73d26f280..2ff5421c7ea9 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.18.1", + "version": "1.19.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -36,12 +36,12 @@ }, "dependencies": { "@chainsafe/ssz": "^0.15.1", - "@lodestar/config": "^1.18.1", - "@lodestar/utils": "^1.18.1", - "it-all": "^3.0.4", - "level": "^8.0.0" + "@lodestar/config": "^1.19.0", + "@lodestar/utils": "^1.19.0", + "classic-level": "^1.4.1", + "it-all": "^3.0.4" }, "devDependencies": { - "@lodestar/logger": "^1.18.1" + "@lodestar/logger": "^1.19.0" } } diff --git a/packages/db/src/controller/level.ts b/packages/db/src/controller/level.ts index 1a8f75ed875c..07ebef8e8a22 100644 --- a/packages/db/src/controller/level.ts +++ b/packages/db/src/controller/level.ts @@ -1,5 +1,4 @@ -import {Level} from "level"; -import type {ClassicLevel} from "classic-level"; +import {ClassicLevel} from "classic-level"; import {Logger} from "@lodestar/utils"; import {DbReqOpts, DatabaseController, DatabaseOptions, FilterOptions, KeyValue} from "./interface.js"; import {LevelDbControllerMetrics} from "./metrics.js"; @@ -9,10 +8,8 @@ enum Status { closed = "closed", } -type LevelNodeJS = ClassicLevel; - export interface LevelDBOptions extends DatabaseOptions { - db?: Level; + db?: ClassicLevel; } export type LevelDbControllerModules = { @@ -35,7 +32,7 @@ export class LevelDbController implements DatabaseController, + private readonly db: ClassicLevel, private metrics: LevelDbControllerMetrics | null ) { this.metrics = metrics ?? null; @@ -46,7 +43,8 @@ export class LevelDbController implements DatabaseController { - const db = opts.db || new Level(opts.name || "beaconchain", {keyEncoding: "binary", valueEncoding: "binary"}); + const db = + opts.db || new ClassicLevel(opts.name || "beaconchain", {keyEncoding: "binary", valueEncoding: "binary"}); try { await db.open(); @@ -162,14 +160,14 @@ export class LevelDbController implements DatabaseController { - return (this.db as LevelNodeJS).approximateSize(start, end); + return this.db.approximateSize(start, end); } /** * Manually trigger a database compaction in the range [start..end]. */ compactRange(start: Uint8Array, end: Uint8Array): Promise { - return (this.db as LevelNodeJS).compactRange(start, end); + return this.db.compactRange(start, end); } /** Capture metrics for db.iterator, db.keys, db.values .all() calls */ @@ -221,6 +219,10 @@ export class LevelDbController implements DatabaseController { + return ClassicLevel.destroy(location); + } } /** From https://www.npmjs.com/package/level */ diff --git a/packages/db/test/unit/controller/level.test.ts b/packages/db/test/unit/controller/level.test.ts index 33d5b9a86c2a..11ef0f929fda 100644 --- a/packages/db/test/unit/controller/level.test.ts +++ b/packages/db/test/unit/controller/level.test.ts @@ -1,7 +1,6 @@ import {execSync} from "node:child_process"; import os from "node:os"; import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import leveldown from "leveldown"; import all from "it-all"; import {getEnvLogger} from "@lodestar/logger/env"; import {LevelDbController} from "../../../src/controller/index.js"; @@ -16,12 +15,7 @@ describe("LevelDB controller", () => { afterAll(async () => { await db.close(); - await new Promise((resolve, reject) => { - leveldown.destroy(dbLocation, (err) => { - if (err) reject(err); - else resolve(); - }); - }); + await LevelDbController.destroy(dbLocation); }); it("test get not found", async () => { diff --git a/packages/flare/README.md b/packages/flare/README.md index 11c18802c3ee..b644d5592314 100644 --- a/packages/flare/README.md +++ b/packages/flare/README.md @@ -2,7 +2,7 @@ [![npm](https://img.shields.io/npm/v/@lodestar/flare)](https://www.npmjs.com/package/@lodestar/flare) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) ![Node Version](https://img.shields.io/badge/node-12.x-green) diff --git a/packages/flare/package.json b/packages/flare/package.json index 8d20b6d4d4e1..54a0dbec51f5 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.18.1", + "version": "1.19.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls": "7.1.3", "@chainsafe/bls-keygen": "^0.4.0", - "@lodestar/api": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/state-transition": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/api": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/state-transition": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", "source-map-support": "^0.5.21", "yargs": "^17.7.1" }, diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 09d2bebe9427..1a1b20bfe6e1 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -37,11 +37,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.15.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/state-transition": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1" + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/state-transition": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0" }, "keywords": [ "ethereum", diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 7adc2c425816..8ba3156a1b9a 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -281,7 +281,7 @@ export class ForkChoice implements IForkChoice { const parentNode = this.protoArray.getNode(parentBlock.blockRoot); // If parentNode is unavailable, give up reorg if (parentNode === undefined || parentNode.weight <= parentThreshold) { - return {proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ParentBlockIsStrong}; + return {proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ParentBlockNotStrong}; } // Reorg if all above checks fail diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 5086013bd3a1..e4d087deab3a 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -53,7 +53,7 @@ export enum NotReorgedReason { ReorgMoreThanOneSlot, ProposerBoostNotWornOff, HeadBlockNotWeak, - ParentBlockIsStrong, + ParentBlockNotStrong, NotProposingOnTime, } diff --git a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts index 9764b18068bb..661d3b45ed68 100644 --- a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts @@ -193,7 +193,7 @@ describe("Forkchoice / GetProposerHead", function () { parentBlock: {...baseParentHeadBlock, weight: 211}, headBlock: {...baseHeadBlock}, expectReorg: false, - expectedNotReorgedReason: NotReorgedReason.ParentBlockIsStrong, + expectedNotReorgedReason: NotReorgedReason.ParentBlockNotStrong, }, { id: "No reorg if not proposing on time", diff --git a/packages/light-client/README.md b/packages/light-client/README.md index 5fdcae6a3e10..dd00777f81b5 100644 --- a/packages/light-client/README.md +++ b/packages/light-client/README.md @@ -9,7 +9,7 @@ The evolution of light clients is emblematic of the broader trajectory of Ethere ## Prerequisites [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) ![Node Version](https://img.shields.io/badge/node-16.x-green) ![Yarn](https://img.shields.io/badge/yarn-%232C8EBB.svg?style=for-the-badge&logo=yarn&logoColor=white) @@ -41,26 +41,29 @@ It is possible to start up the light-client as a standalone process. ```bash lodestar lightclient \ - --network mainnet \ - --beacon-api-url https://beacon-node.your-domain.com \ + --network sepolia \ + --beacon-api-url https://lodestar-sepolia.chainsafe.io \ --checkpoint-root "0xccaff4b99986a7b05e06738f1828a32e40799b277fd9f9ff069be55341fe0229" ``` ## Light-Client Programmatic Example -For this example we will assume there is a running beacon node at `https://beacon-node.your-domain.com` +For this example we will assume there is a running beacon node at `https://lodestar-sepolia.chainsafe.io` ```ts -import {getClient} from "@lodestar/api"; -import {createChainForkConfig} from "@lodestar/config"; -import {networksChainConfig} from "@lodestar/config/networks"; import {Lightclient, LightclientEvent} from "@lodestar/light-client"; import {LightClientRestTransport} from "@lodestar/light-client/transport"; -import {getFinalizedSyncCheckpoint, getGenesisData, getLcLoggerConsole} from "@lodestar/light-client/utils"; - -const config = createChainForkConfig(networksChainConfig.mainnet); -const logger = getLcLoggerConsole({logDebug: Boolean(process.env.DEBUG)}); -const api = getClient({urls: ["https://beacon-node.your-domain.com"]}, {config}); +import { + getFinalizedSyncCheckpoint, + getGenesisData, + getConsoleLogger, + getApiFromUrl, + getChainForkConfigFromNetwork, +} from "@lodestar/light-client/utils"; + +const config = getChainForkConfigFromNetwork("sepolia"); +const logger = getConsoleLogger({logDebug: Boolean(process.env.DEBUG)}); +const api = getApiFromUrl({urls: ["https://lodestar-sepolia.chainsafe.io"]}, {config}); const lightclient = await Lightclient.initializeFromCheckpointRoot({ config, @@ -88,6 +91,35 @@ lightclient.emitter.on(LightclientEvent.lightClientOptimisticHeader, async (opti }); ``` +## Browser Integration + +If you want to use Lightclient in browser and facing some issues in building it with bundlers like webpack, vite. We suggest to use our distribution build. The support for single distribution build is started from `1.19.0` version. + +Directly link the dist build with the ` + +**Typescript support** The web bundle comes with the types support. Unfortunately due to following +[issue](https://github.com/microsoft/rushstack/issues/1128#issuecomment-2066257538) we can't bundle all types. A +workaround would be to add `@chainsafe/as-sha256` as a devDependency to your project. +``` + ## Contributors Read our [contribution documentation](https://chainsafe.github.io/lodestar/contribution/getting-started), [submit an issue](https://github.com/ChainSafe/lodestar/issues/new/choose) or talk to us on our [discord](https://discord.gg/yjyvFRP)! diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 641cec171823..4f79eeb61274 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -45,22 +45,29 @@ "lib/**/*.js", "lib/**/*.js.map", "*.d.ts", - "*.js" + "*.js", + "dist/**/*.js", + "dist/**/*.mjs", + "dist/**/*.cjs", + "dist/**/*.map", + "dist/**/*.json", + "dist/**/*.d.ts" ], "scripts": { "clean": "rm -rf lib && rm -f *.tsbuildinfo", "build": "tsc -p tsconfig.build.json", + "build:dist": "vite build", "build:watch": "yarn run build --watch", - "build:release": "yarn clean && yarn run build", + "build:release": "yarn clean && yarn run build && yarn run build:dist", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", - "check-types": "tsc", + "check-types": "yarn run build:dist && tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", - "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", - "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", + "test:browsers:chrome": "yarn run build:dist && vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", + "test:browsers:firefox": "yarn run build:dist && vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", "check-readme": "typescript-docs-verifier" }, @@ -68,17 +75,17 @@ "@chainsafe/bls": "7.1.3", "@chainsafe/persistent-merkle-tree": "^0.7.1", "@chainsafe/ssz": "^0.15.1", - "@lodestar/api": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/api": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", "mitt": "^3.0.0" }, "devDependencies": { "@chainsafe/as-sha256": "^0.4.1", "@types/qs": "^6.9.7", - "fastify": "^4.26.2", + "fastify": "^4.27.0", "qs": "^6.11.1", "uint8arrays": "^5.0.1" }, diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index 7fe6332895af..63996a8fda18 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -7,7 +7,7 @@ import {isErrorAborted, sleep} from "@lodestar/utils"; import {getCurrentSlot, slotWithFutureTolerance, timeUntilNextEpoch} from "./utils/clock.js"; import {chunkifyInclusiveRange} from "./utils/chunkify.js"; import {LightclientEmitter, LightclientEvent} from "./events.js"; -import {getLcLoggerConsole, ILcLogger} from "./utils/logger.js"; +import {getConsoleLogger, ILcLogger} from "./utils/logger.js"; import {computeSyncPeriodAtEpoch, computeSyncPeriodAtSlot, computeEpochAtSlot} from "./utils/clock.js"; import {LightclientSpec} from "./spec/index.js"; import {validateLightClientBootstrap} from "./spec/validateLightClientBootstrap.js"; @@ -114,7 +114,7 @@ export class Lightclient { : genesisData.genesisValidatorsRoot; this.config = createBeaconConfig(config, this.genesisValidatorsRoot); - this.logger = logger ?? getLcLoggerConsole(); + this.logger = logger ?? getConsoleLogger(); this.transport = transport; this.runStatus = {code: RunStatusCode.uninitialized}; @@ -318,3 +318,9 @@ export class Lightclient { this.emitter.emit(LightclientEvent.statusChange, this.runStatus.code); } } + +// To export these name spaces to the bundle JS +import * as utils from "./utils.js"; +import * as validation from "./validation.js"; +import * as transport from "./transport.js"; +export {utils, validation, transport}; diff --git a/packages/light-client/src/transport.ts b/packages/light-client/src/transport.ts new file mode 100644 index 000000000000..b39186faded4 --- /dev/null +++ b/packages/light-client/src/transport.ts @@ -0,0 +1,2 @@ +// This file exists to have proper namespace for the web bundle +export * from "./transport/index.js"; diff --git a/packages/light-client/src/utils.ts b/packages/light-client/src/utils.ts new file mode 100644 index 000000000000..eaa5264eb4cb --- /dev/null +++ b/packages/light-client/src/utils.ts @@ -0,0 +1,2 @@ +// This file exists to have proper namespace for the web bundle +export * from "./utils/index.js"; diff --git a/packages/light-client/src/utils/api.ts b/packages/light-client/src/utils/api.ts new file mode 100644 index 000000000000..bcc8a4d4f29c --- /dev/null +++ b/packages/light-client/src/utils/api.ts @@ -0,0 +1,19 @@ +import {getClient, Api} from "@lodestar/api"; +import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; +import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; + +export function getApiFromUrl(url: string, network: NetworkName): Api { + if (!(network in networksChainConfig)) { + throw Error(`Invalid network name "${network}". Valid options are: ${Object.keys(networksChainConfig).join()}`); + } + + return getClient({urls: [url]}, {config: createChainForkConfig(networksChainConfig[network])}); +} + +export function getChainForkConfigFromNetwork(network: NetworkName): ChainForkConfig { + if (!(network in networksChainConfig)) { + throw Error(`Invalid network name "${network}". Valid options are: ${Object.keys(networksChainConfig).join()}`); + } + + return createChainForkConfig(networksChainConfig[network]); +} diff --git a/packages/light-client/src/utils/index.ts b/packages/light-client/src/utils/index.ts index 145e6fe52c9a..6c49c7ed11f9 100644 --- a/packages/light-client/src/utils/index.ts +++ b/packages/light-client/src/utils/index.ts @@ -1,3 +1,4 @@ +export * from "./api.js"; export * from "./chunkify.js"; export * from "./clock.js"; export * from "./domain.js"; diff --git a/packages/light-client/src/utils/logger.ts b/packages/light-client/src/utils/logger.ts index cb47857da165..afdbf7da7d3d 100644 --- a/packages/light-client/src/utils/logger.ts +++ b/packages/light-client/src/utils/logger.ts @@ -13,7 +13,7 @@ export type ILcLogger = { /** * With `console` module and ignoring debug logs */ -export function getLcLoggerConsole(opts?: {logDebug?: boolean}): ILcLogger { +export function getConsoleLogger(opts?: {logDebug?: boolean}): ILcLogger { return { error: console.error, warn: console.warn, @@ -21,3 +21,8 @@ export function getLcLoggerConsole(opts?: {logDebug?: boolean}): ILcLogger { debug: opts?.logDebug ? console.log : () => {}, }; } + +/** + * @deprecated - Use `getConsoleLogger` instead. + */ +export const getLcLoggerConsole = getConsoleLogger; diff --git a/packages/light-client/test/mocks/LightclientServerApiMock.ts b/packages/light-client/test/mocks/LightclientServerApiMock.ts index 941e623ba1c8..0b6676ccdac1 100644 --- a/packages/light-client/test/mocks/LightclientServerApiMock.ts +++ b/packages/light-client/test/mocks/LightclientServerApiMock.ts @@ -1,4 +1,4 @@ -import {concat} from "uint8arrays"; +import {concat} from "uint8arrays/concat"; import {digest} from "@chainsafe/as-sha256"; import {createProof, Proof, ProofType} from "@chainsafe/persistent-merkle-tree"; import {routes, ServerApi} from "@lodestar/api"; diff --git a/packages/light-client/test/unit/webEsmBundle.browser.test.ts b/packages/light-client/test/unit/webEsmBundle.browser.test.ts new file mode 100644 index 000000000000..64f944888184 --- /dev/null +++ b/packages/light-client/test/unit/webEsmBundle.browser.test.ts @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ +import {expect, describe, it, vi} from "vitest"; +import {Lightclient, LightclientEvent, utils, transport} from "../../dist/lightclient.min.mjs"; + +describe("web bundle for lightclient", () => { + vi.setConfig({testTimeout: 20_000}); + + it("should have a global interface", () => { + expect((window as any)["lodestar"]["lightclient"]).toBeDefined(); + }); + + it("should have all relevant exports", () => { + const lightclient = (window as any)["lodestar"]["lightclient"]; + expect(lightclient).toHaveProperty("Lightclient"); + expect(lightclient).toHaveProperty("LightclientEvent"); + expect(lightclient).toHaveProperty("RunStatusCode"); + expect(lightclient).toHaveProperty("upgradeLightClientFinalityUpdate"); + expect(lightclient).toHaveProperty("upgradeLightClientOptimisticUpdate"); + expect(lightclient).toHaveProperty("utils"); + expect(lightclient).toHaveProperty("transport"); + expect(lightclient).toHaveProperty("validation"); + + expect(lightclient.Lightclient).toBeTypeOf("function"); + }); + + it("should start the lightclient and sync", async () => { + const logger = utils.getConsoleLogger({logDebug: true}); + const config = utils.getChainForkConfigFromNetwork("mainnet"); + + // TODO: Decide to check which node to use in testing + // We have one node in CI, but that only starts with e2e tests + const api = utils.getApiFromUrl("https://lodestar-mainnet.chainsafe.io", "mainnet"); + + const lc = await Lightclient.initializeFromCheckpointRoot({ + config, + logger, + transport: new transport.LightClientRestTransport(api), + genesisData: await utils.getGenesisData(api), + checkpointRoot: await utils.getFinalizedSyncCheckpoint(api), + opts: { + allowForcedUpdates: true, + updateHeadersOnForcedUpdate: true, + }, + }); + + await expect(lc.start()).resolves.toBeUndefined(); + + await expect( + new Promise((resolve) => { + lc.emitter.on(LightclientEvent.lightClientOptimisticHeader, async (optimisticUpdate: unknown) => { + resolve(optimisticUpdate); + }); + }) + ).resolves.toBeDefined(); + }); +}); diff --git a/packages/light-client/test/utils/utils.ts b/packages/light-client/test/utils/utils.ts index 930cabfdad11..a99004345217 100644 --- a/packages/light-client/test/utils/utils.ts +++ b/packages/light-client/test/utils/utils.ts @@ -14,7 +14,7 @@ import { import {altair, phase0, Slot, ssz, SyncPeriod, allForks} from "@lodestar/types"; import {SyncCommitteeFast} from "../../src/types.js"; import {computeSigningRoot} from "../../src/utils/domain.js"; -import {getLcLoggerConsole} from "../../src/utils/logger.js"; +import {getConsoleLogger} from "../../src/utils/logger.js"; const CURRENT_SYNC_COMMITTEE_INDEX = 22; const CURRENT_SYNC_COMMITTEE_DEPTH = 5; @@ -25,7 +25,7 @@ const CURRENT_SYNC_COMMITTEE_DEPTH = 5; * DEBUG=true vitest ... * ``` */ -export const testLogger = getLcLoggerConsole({logDebug: Boolean(process.env.DEBUG)}); +export const testLogger = getConsoleLogger({logDebug: Boolean(process.env.DEBUG)}); export const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); export const SOME_HASH = Buffer.alloc(32, 0xaa); diff --git a/packages/light-client/tsconfig.json b/packages/light-client/tsconfig.json index b29a7b46c4b1..cfcb3522f506 100644 --- a/packages/light-client/tsconfig.json +++ b/packages/light-client/tsconfig.json @@ -1,4 +1,5 @@ { "extends": "../../tsconfig.json", + "exclude": ["src/index.browser.ts"], "compilerOptions": {} } diff --git a/packages/light-client/vite.config.ts b/packages/light-client/vite.config.ts new file mode 100644 index 000000000000..ff1f566fd289 --- /dev/null +++ b/packages/light-client/vite.config.ts @@ -0,0 +1,44 @@ +import path from "node:path"; +import fs from "node:fs"; +import {defineConfig, mergeConfig} from "vite"; +import dts from "vite-plugin-dts"; +import {getBaseViteConfig} from "../../vite.base.config.js"; + +import pkgJSON from "./package.json"; + +export default mergeConfig( + getBaseViteConfig(pkgJSON, {libName: "LightClient", entry: "src/index.ts"}), + defineConfig({ + plugins: [ + dts({ + rollupTypes: true, + bundledPackages: ["@lodestar/*", "@chainsafe/persistent-merkle-tree", "@chainsafe/bls", "@chainsafe/ssz"], + afterBuild() { + fs.renameSync( + path.join(import.meta.dirname, "dist", "index.d.ts"), + path.join(import.meta.dirname, "dist", "lightclient.min.d.mts") + ); + }, + }), + ], + build: { + rollupOptions: { + output: { + footer: ` + globalThis.lodestar = globalThis.lodestar === undefined ? {} : globalThis.lodestar; + globalThis.lodestar.lightclient = { + Lightclient, + LightclientEvent, + RunStatusCode, + upgradeLightClientFinalityUpdate, + upgradeLightClientOptimisticUpdate, + utils, + transport, + validation + }; + `, + }, + }, + }, + }) +); diff --git a/packages/logger/package.json b/packages/logger/package.json index 0caf2bf87786..71c7623fb028 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.18.1", + "@lodestar/utils": "^1.19.0", "winston": "^3.8.2", "winston-daily-rotate-file": "^4.7.1", "winston-transport": "^4.5.0" }, "devDependencies": { "@chainsafe/threads": "^1.11.1", - "@lodestar/test-utils": "^1.18.1", + "@lodestar/test-utils": "^1.19.0", "@types/triple-beam": "^1.3.2", "triple-beam": "^1.3.0" }, diff --git a/packages/params/README.md b/packages/params/README.md index d1f3082edfac..730b27276f09 100644 --- a/packages/params/README.md +++ b/packages/params/README.md @@ -2,9 +2,9 @@ [![npm](https://img.shields.io/npm/v/@lodestar/types)](https://www.npmjs.com/package/@lodestar/types) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/params/package.json b/packages/params/package.json index 47c86756688c..758e62feb178 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.18.1", + "version": "1.19.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/README.md b/packages/prover/README.md index 8d43fd861473..b377448a1726 100644 --- a/packages/prover/README.md +++ b/packages/prover/README.md @@ -3,7 +3,7 @@ [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) [![ETH Beacon APIs Spec v2.1.0](https://img.shields.io/badge/ETH%20beacon--APIs-2.1.0-blue)](https://github.com/ethereum/beacon-APIs/releases/tag/v2.1.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project @@ -17,15 +17,39 @@ You can use the `@lodestar/prover` in two ways, as a Web3 Provider and as proxy. import Web3 from "web3"; import {createVerifiedExecutionProvider, LCTransport} from "@lodestar/prover"; -const {provider, proofProvider} = createVerifiedExecutionProvider( - new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"), - { - transport: LCTransport.Rest, - urls: ["https://lodestar-sepolia.chainsafe.io"], - network: "sepolia", - wsCheckpoint: "trusted-checkpoint", - } -); +const httpProvider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); + +const {provider, proofProvider} = createVerifiedExecutionProvider(httpProvider, { + transport: LCTransport.Rest, + urls: ["https://lodestar-sepolia.chainsafe.io"], + network: "sepolia", + wsCheckpoint: "trusted-checkpoint", +}); + +const web3 = new Web3(provider); + +const address = "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134"; +const balance = await web3.eth.getBalance(address, "latest"); +console.log({balance, address}); +``` + +In this scenario the actual provider is mutated to handle the RPC requests and verify those. So here if you use `provider` or `httpProvider` both are the same objects. This behavior is useful when you already have an application and usage of any provider across the code space and don't want to change the code. So you mutate the provider during startup. + +For some scenarios when you don't want to mutate the provider you can pass an option `mutateProvider` as `false`. In this scenario the object `httpProvider` is not mutated and you get a new object `provider`. This is useful when your provider object does not allow mutation, e.g. Metamask provider accessible through `window.ethereum`. If not provided `mutateProvider` is considered as `true` by default. In coming releases we will switch its default behavior to `false`. + +```ts +import Web3 from "web3"; +import {createVerifiedExecutionProvider, LCTransport} from "@lodestar/prover"; + +const httpProvider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); + +const {provider, proofProvider} = createVerifiedExecutionProvider(httpProvider, { + transport: LCTransport.Rest, + urls: ["https://lodestar-sepolia.chainsafe.io"], + network: "sepolia", + wsCheckpoint: "trusted-checkpoint", + mutateProvider: false, +}); const web3 = new Web3(provider); @@ -46,6 +70,12 @@ lodestar-prover proxy \ --port 8080 ``` +## How to detect a web3 provider + +There can be different implementations of the web3 providers and each can handle the RPC request differently. We call those different provider types. We had provided builtin support for common providers e.g. web3.js, ethers or any eip1193 compatible providers. We inspect given provider instance at runtime to detect the correct provider type. + +If your project is using some provider type which is not among above list, you have the option to register a custom provider type with the `createVerifiedExecutionProvider` with the option `providerTypes` which will be an array of your supported provider types. Your custom provider types will have higher priority than default provider types. Please see [existing provide types implementations](./src/provider_types/) to know how to implement your own if needed. + ## Supported Web3 Methods ✅ - Completed diff --git a/packages/prover/package.json b/packages/prover/package.json index 9a90d27055a6..9d4cb905e59b 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -69,13 +69,13 @@ "@ethereumjs/tx": "^4.1.2", "@ethereumjs/util": "^8.0.6", "@ethereumjs/vm": "^6.4.2", - "@lodestar/api": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/light-client": "^1.18.1", - "@lodestar/logger": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/api": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/light-client": "^1.19.0", + "@lodestar/logger": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", "ethereum-cryptography": "^2.0.0", "find-up": "^6.3.0", "http-proxy": "^1.18.1", @@ -84,7 +84,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.18.1", + "@lodestar/test-utils": "^1.19.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/prover/src/interfaces.ts b/packages/prover/src/interfaces.ts index 334bc48837a8..36222c1476d3 100644 --- a/packages/prover/src/interfaces.ts +++ b/packages/prover/src/interfaces.ts @@ -3,7 +3,7 @@ import {NetworkName} from "@lodestar/config/networks"; import {Logger, LogLevel} from "@lodestar/utils"; import {ProofProvider} from "./proof_provider/proof_provider.js"; import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "./types.js"; -import {ELRpc} from "./utils/rpc.js"; +import {ELRpcProvider} from "./utils/rpc_provider.js"; export type {NetworkName} from "@lodestar/config/networks"; export enum LCTransport { @@ -30,50 +30,14 @@ export type ELRequestHandler = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ELRequestHandlerAny = ELRequestHandler; -// Modern providers uses this structure e.g. Web3 4.x -export interface EIP1193Provider { - request: (payload: JsonRpcRequestOrBatch) => Promise; -} - -export interface Web3jsProvider { - request: (payload: JsonRpcRequest) => Promise; -} - -// Some providers uses `request` instead of the `send`. e.g. Ganache -export interface RequestProvider { - request( - payload: JsonRpcRequestOrBatch, - callback: (err: Error | undefined, response: JsonRpcResponseOrBatch) => void - ): void; -} - -// The legacy Web3 1.x use this structure -export interface SendProvider { - send(payload: JsonRpcRequest, callback: (err?: Error | null, response?: JsonRpcResponse) => void): void; -} - -// Ethers provider uses this structure -export interface EthersProvider { - // Ethers provider does not have a public interface for batch requests - send(method: string, params: Array): Promise; -} - -// Some legacy providers use this very old structure -export interface SendAsyncProvider { - sendAsync(payload: JsonRpcRequestOrBatch): Promise; -} - -export type Web3Provider = - | SendProvider - | EthersProvider - | SendAsyncProvider - | RequestProvider - | EIP1193Provider - | Web3jsProvider; +/** + * @deprecated Kept for backward compatibility. Use `AnyWeb3Provider` type instead. + */ +export type Web3Provider = object; export type ELVerifiedRequestHandlerOpts = { payload: JsonRpcRequest; - rpc: ELRpc; + rpc: ELRpcProvider; proofProvider: ProofProvider; logger: Logger; }; @@ -96,4 +60,31 @@ export type RootProviderOptions = { unverifiedWhitelist?: string[]; }; -export type VerifiedExecutionInitOptions = LogOptions & ConsensusNodeOptions & NetworkOrConfig & RootProviderOptions; +export type ProviderTypeOptions = { + /** + * If user specify custom provider types we will register those at the start in given order. + * So if you provider [custom1, custom2] and we already have [web3js, ethers] then final order + * of providers will be [custom1, custom2, web3js, ethers] + */ + providerTypes?: Web3ProviderType[]; + /** + * To keep the backward compatible behavior if this option is not set we consider `true` as default. + * In coming breaking release we may set this option default to `false`. + */ + mutateProvider?: T; +}; + +export type VerifiedExecutionInitOptions = LogOptions & + ConsensusNodeOptions & + NetworkOrConfig & + RootProviderOptions & + ProviderTypeOptions; + +export type AnyWeb3Provider = object; + +export interface Web3ProviderType { + name: string; + matched: (provider: AnyWeb3Provider) => provider is T; + handler(provider: T): ELRpcProvider["handler"]; + mutateProvider(provider: T, newHandler: ELRpcProvider["handler"]): void; +} diff --git a/packages/prover/src/provider_types/eip1193_provider_type.ts b/packages/prover/src/provider_types/eip1193_provider_type.ts new file mode 100644 index 000000000000..98f41482951a --- /dev/null +++ b/packages/prover/src/provider_types/eip1193_provider_type.ts @@ -0,0 +1,32 @@ +import {Web3ProviderType} from "../interfaces.js"; +import {JsonRpcRequestOrBatch, JsonRpcResponseOrBatch} from "../types.js"; + +// Modern providers uses this structure e.g. Web3 4.x +export interface EIP1193Provider { + request: (payload: JsonRpcRequestOrBatch) => Promise; +} +export default { + name: "eip1193", + matched(provider): provider is EIP1193Provider { + return ( + "request" in provider && + typeof provider.request === "function" && + provider.request.constructor.name === "AsyncFunction" + ); + }, + handler(provider) { + const request = provider.request.bind(provider); + + return async (payload: JsonRpcRequestOrBatch): Promise => { + const response = await request(payload); + return response; + }; + }, + mutateProvider(provider, newHandler) { + Object.assign(provider, { + request: async function newRequest(payload: JsonRpcRequestOrBatch): Promise { + return newHandler(payload); + }, + }); + }, +} as Web3ProviderType; diff --git a/packages/prover/src/provider_types/ethers_provider_type.ts b/packages/prover/src/provider_types/ethers_provider_type.ts new file mode 100644 index 000000000000..208e901520fa --- /dev/null +++ b/packages/prover/src/provider_types/ethers_provider_type.ts @@ -0,0 +1,44 @@ +import {Web3ProviderType} from "../interfaces.js"; +import {JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "../types.js"; +import {isBatchRequest} from "../utils/json_rpc.js"; +import web3JsProviderType from "./web3_js_provider_type.js"; + +export interface EthersProvider { + // Ethers provider does not have a public interface for batch requests + send(method: string, params: Array): Promise; +} +export default { + name: "ethers", + matched(provider): provider is EthersProvider { + return ( + !web3JsProviderType.matched(provider) && + "send" in provider && + typeof provider.send === "function" && + provider.send.length > 1 && + provider.send.constructor.name === "AsyncFunction" + ); + }, + handler(provider) { + const send = provider.send.bind(provider); + + return async (payload: JsonRpcRequestOrBatch): Promise => { + // Because ethers provider public interface does not support batch requests + // so we need to handle it manually + if (isBatchRequest(payload)) { + const responses = []; + for (const request of payload) { + responses.push(await send(request.method, request.params)); + } + return responses; + } + return send(payload.method, payload.params); + }; + }, + mutateProvider(provider, newHandler) { + Object.assign(provider, { + send: function newSend(method: string, params: Array): Promise { + return newHandler({jsonrpc: "2.0", id: 0, method, params}); + }, + }); + }, +} as Web3ProviderType; diff --git a/packages/prover/src/provider_types/legacy_provider_type.ts b/packages/prover/src/provider_types/legacy_provider_type.ts new file mode 100644 index 000000000000..7dbbe7598e66 --- /dev/null +++ b/packages/prover/src/provider_types/legacy_provider_type.ts @@ -0,0 +1,123 @@ +import {AnyWeb3Provider, Web3ProviderType} from "../interfaces.js"; +import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "../types.js"; +import web3JsProviderType from "./web3_js_provider_type.js"; + +// Some providers uses `request` instead of the `send`. e.g. Ganache +interface RequestProvider { + request( + payload: JsonRpcRequestOrBatch, + callback: (err: Error | undefined, response: JsonRpcResponseOrBatch) => void + ): void; +} +// The legacy Web3 1.x use this structure +interface SendProvider { + send(payload: JsonRpcRequest, callback: (err?: Error | null, response?: JsonRpcResponse) => void): void; +} +// Some legacy providers use this very old structure +interface SendAsyncProvider { + sendAsync(payload: JsonRpcRequestOrBatch): Promise; +} + +type LegacyProvider = RequestProvider | SendProvider | SendAsyncProvider; + +export default { + name: "legacy", + matched(provider): provider is LegacyProvider { + return isRequestProvider(provider) || isSendProvider(provider) || isSendAsyncProvider(provider); + }, + handler(provider) { + if (isRequestProvider(provider)) { + const request = provider.request.bind(provider); + return function newHandler(payload: JsonRpcRequestOrBatch): Promise { + return new Promise((resolve, reject) => { + request(payload, (err, response) => { + if (err) { + reject(err); + } else { + resolve(response); + } + }); + }); + }; + } + if (isSendProvider(provider)) { + const send = provider.send.bind(provider); + return function newHandler(payload: JsonRpcRequestOrBatch): Promise { + return new Promise((resolve, reject) => { + // web3 providers supports batch requests but don't have valid types + send(payload as JsonRpcRequest, (err, response) => { + if (err) { + reject(err); + } else { + resolve(response); + } + }); + }); + }; + } + + // sendAsync provider + const sendAsync = provider.sendAsync.bind(provider); + return async function newHandler(payload: JsonRpcRequestOrBatch): Promise { + const response = await sendAsync(payload); + return response; + }; + }, + mutateProvider(provider, newHandler) { + if (isRequestProvider(provider)) { + const newRequest = function newRequest( + payload: JsonRpcRequestOrBatch, + callback: (err?: Error | null, response?: JsonRpcResponseOrBatch) => void + ): void { + newHandler(payload) + .then((response) => callback(undefined, response)) + .catch((err) => callback(err, undefined)); + }; + + Object.assign(provider, {request: newRequest}); + } + + if (isSendProvider(provider)) { + const newSend = function newSend( + payload: JsonRpcRequestOrBatch, + callback: (err?: Error | null, response?: JsonRpcResponseOrBatch) => void + ): void { + newHandler(payload) + .then((response) => callback(undefined, response)) + .catch((err) => callback(err, undefined)); + }; + + Object.assign(provider, {send: newSend}); + } + + // sendAsync provider + Object.assign(provider, {sendAsync: newHandler}); + }, +} as Web3ProviderType; + +function isSendProvider(provider: AnyWeb3Provider): provider is SendProvider { + return ( + !web3JsProviderType.matched(provider) && + "send" in provider && + typeof provider.send === "function" && + provider.send.length > 1 && + provider.send.constructor.name !== "AsyncFunction" + ); +} + +function isRequestProvider(provider: AnyWeb3Provider): provider is RequestProvider { + return ( + !web3JsProviderType.matched(provider) && + "request" in provider && + typeof provider.request === "function" && + provider.request.length > 1 + ); +} + +function isSendAsyncProvider(provider: AnyWeb3Provider): provider is SendAsyncProvider { + return ( + "sendAsync" in provider && + typeof provider.sendAsync === "function" && + provider.sendAsync.constructor.name === "AsyncFunction" + ); +} diff --git a/packages/prover/src/provider_types/web3_js_provider_type.ts b/packages/prover/src/provider_types/web3_js_provider_type.ts new file mode 100644 index 000000000000..bc95d47a6f7f --- /dev/null +++ b/packages/prover/src/provider_types/web3_js_provider_type.ts @@ -0,0 +1,35 @@ +import {AnyWeb3Provider, Web3ProviderType} from "../interfaces.js"; +import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "../types.js"; +import {isBatchRequest} from "../utils/json_rpc.js"; + +export interface Web3jsProvider { + request: (payload: JsonRpcRequest) => Promise; +} + +export default { + name: "web3js", + matched(provider): provider is Web3jsProvider { + return ( + "isWeb3Provider" in provider.constructor && + (provider.constructor as {isWeb3Provider: (provider: AnyWeb3Provider) => boolean}).isWeb3Provider(provider) + ); + }, + handler(provider) { + const request = provider.request.bind(provider); + + return async (payload: JsonRpcRequestOrBatch): Promise => { + if (isBatchRequest(payload)) { + return Promise.all(payload.map((p) => request(p))); + } + + return request(payload); + }; + }, + mutateProvider(provider, newHandler) { + Object.assign(provider, { + request: async function newRequest(payload: JsonRpcRequestOrBatch): Promise { + return newHandler(payload); + }, + }); + }, +} as Web3ProviderType; diff --git a/packages/prover/src/types.ts b/packages/prover/src/types.ts index 58040cafee76..781ba1f7b207 100644 --- a/packages/prover/src/types.ts +++ b/packages/prover/src/types.ts @@ -147,6 +147,7 @@ export type ELStorageProof = Pick; /* eslint-disable @typescript-eslint/naming-convention */ export type ELApi = { + eth_getBalance: (address: string, block?: number | string) => string; eth_createAccessList: (transaction: ELTransaction, block?: ELBlockNumberOrTag) => ELAccessListResponse; eth_call: (transaction: ELTransaction, block?: ELBlockNumberOrTag) => HexString; eth_estimateGas: (transaction: ELTransaction, block?: ELBlockNumberOrTag) => HexString; diff --git a/packages/prover/src/utils/assertion.ts b/packages/prover/src/utils/assertion.ts index e302b9a9200a..82432a031646 100644 --- a/packages/prover/src/utils/assertion.ts +++ b/packages/prover/src/utils/assertion.ts @@ -1,12 +1,4 @@ import {Lightclient} from "@lodestar/light-client"; -import { - EIP1193Provider, - EthersProvider, - RequestProvider, - SendAsyncProvider, - SendProvider, - Web3Provider, -} from "../interfaces.js"; export function assertLightClient(client?: Lightclient): asserts client is Lightclient { if (!client) { @@ -14,62 +6,6 @@ export function assertLightClient(client?: Lightclient): asserts client is Light } } -/** - * Checks if the provider is a web3.js version 4x. - */ -export function isWeb3jsProvider(provider: Web3Provider): provider is EIP1193Provider { - return ( - "isWeb3Provider" in provider.constructor && - (provider.constructor as {isWeb3Provider: (provider: Web3Provider) => boolean}).isWeb3Provider(provider) - ); -} - -export function isSendProvider(provider: Web3Provider): provider is SendProvider { - return ( - !isWeb3jsProvider(provider) && - "send" in provider && - typeof provider.send === "function" && - provider.send.length > 1 && - provider.send.constructor.name !== "AsyncFunction" - ); -} - -export function isEthersProvider(provider: Web3Provider): provider is EthersProvider { - return ( - !isWeb3jsProvider(provider) && - "send" in provider && - typeof provider.send === "function" && - provider.send.length > 1 && - provider.send.constructor.name === "AsyncFunction" - ); -} - -export function isRequestProvider(provider: Web3Provider): provider is RequestProvider { - return ( - !isWeb3jsProvider(provider) && - "request" in provider && - typeof provider.request === "function" && - provider.request.length > 1 - ); -} - -export function isSendAsyncProvider(provider: Web3Provider): provider is SendAsyncProvider { - return ( - "sendAsync" in provider && - typeof provider.sendAsync === "function" && - provider.sendAsync.constructor.name === "AsyncFunction" - ); -} - -export function isEIP1193Provider(provider: Web3Provider): provider is EIP1193Provider { - return ( - !isWeb3jsProvider(provider) && - "request" in provider && - typeof provider.request === "function" && - provider.request.constructor.name === "AsyncFunction" - ); -} - export function isTruthy(value: T): value is Exclude { return value !== undefined && value !== null && value !== false; } diff --git a/packages/prover/src/utils/evm.ts b/packages/prover/src/utils/evm.ts index 0b45866ad559..bbdba907c35f 100644 --- a/packages/prover/src/utils/evm.ts +++ b/packages/prover/src/utils/evm.ts @@ -13,7 +13,7 @@ import {bufferToHex, chunkIntoN, cleanObject, hexToBigInt, hexToBuffer, numberTo import {getChainCommon, getTxType} from "./execution.js"; import {isValidResponse} from "./json_rpc.js"; import {isNullish, isValidAccount, isValidCodeHash, isValidStorageKeys} from "./validation.js"; -import {ELRpc} from "./rpc.js"; +import {ELRpcProvider} from "./rpc_provider.js"; export async function createVM({proofProvider}: {proofProvider: ProofProvider}): Promise { const common = getChainCommon(proofProvider.config.PRESET_BASE as string); @@ -39,7 +39,7 @@ export async function getVMWithState({ vm, logger, }: { - rpc: ELRpc; + rpc: ELRpcProvider; vm: VM; executionPayload: allForks.ExecutionPayload; tx: ELTransaction; @@ -160,7 +160,7 @@ export async function executeVMCall({ executionPayload, network, }: { - rpc: ELRpc; + rpc: ELRpcProvider; tx: ELTransaction; vm: VM; executionPayload: allForks.ExecutionPayload; @@ -202,7 +202,7 @@ export async function executeVMTx({ executionPayload, network, }: { - rpc: ELRpc; + rpc: ELRpcProvider; tx: ELTransaction; vm: VM; executionPayload: allForks.ExecutionPayload; diff --git a/packages/prover/src/utils/execution.ts b/packages/prover/src/utils/execution.ts index 083f15e1e5dd..8b0fac1f784e 100644 --- a/packages/prover/src/utils/execution.ts +++ b/packages/prover/src/utils/execution.ts @@ -2,11 +2,14 @@ import {Common, CustomChain, Hardfork} from "@ethereumjs/common"; import {ELApiParams, ELApiReturn, ELTransaction} from "../types.js"; import {isValidResponse} from "./json_rpc.js"; import {isBlockNumber, isPresent} from "./validation.js"; -import {ELRpc} from "./rpc.js"; +import {ELRpcProvider} from "./rpc_provider.js"; export type Optional = Omit & {[P in keyof T]?: T[P] | undefined}; -export async function getELCode(rpc: ELRpc, args: ELApiParams["eth_getCode"]): Promise { +export async function getELCode( + rpc: ELRpcProvider, + args: ELApiParams["eth_getCode"] +): Promise { const codeResult = await rpc.request("eth_getCode", args, {raiseError: false}); if (!isValidResponse(codeResult)) { @@ -16,7 +19,10 @@ export async function getELCode(rpc: ELRpc, args: ELApiParams["eth_getCode"]): P return codeResult.result; } -export async function getELProof(rpc: ELRpc, args: ELApiParams["eth_getProof"]): Promise { +export async function getELProof( + rpc: ELRpcProvider, + args: ELApiParams["eth_getProof"] +): Promise { const proof = await rpc.request("eth_getProof", args, {raiseError: false}); if (!isValidResponse(proof)) { throw new Error(`Can not find proof for address=${args[0]}`); @@ -25,7 +31,7 @@ export async function getELProof(rpc: ELRpc, args: ELApiParams["eth_getProof"]): } export async function getELBlock( - rpc: ELRpc, + rpc: ELRpcProvider, args: ELApiParams["eth_getBlockByNumber"] ): Promise { const block = await rpc.request(isBlockNumber(args[0]) ? "eth_getBlockByNumber" : "eth_getBlockByHash", args, { diff --git a/packages/prover/src/utils/process.ts b/packages/prover/src/utils/process.ts index 49bff6a840d2..26768ffce1fb 100644 --- a/packages/prover/src/utils/process.ts +++ b/packages/prover/src/utils/process.ts @@ -11,7 +11,7 @@ import {eth_call} from "../verified_requests/eth_call.js"; import {eth_estimateGas} from "../verified_requests/eth_estimateGas.js"; import {getResponseForRequest, isBatchRequest, isRequest} from "./json_rpc.js"; import {isNullish} from "./validation.js"; -import {ELRpc} from "./rpc.js"; +import {ELRpcProvider} from "./rpc_provider.js"; /* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */ export const verifiableMethodHandlers: Record> = { @@ -69,7 +69,7 @@ export async function processAndVerifyRequest({ logger, }: { payload: JsonRpcRequestOrBatch; - rpc: ELRpc; + rpc: ELRpcProvider; proofProvider: ProofProvider; logger: Logger; }): Promise { diff --git a/packages/prover/src/utils/rpc.ts b/packages/prover/src/utils/rpc_provider.ts similarity index 87% rename from packages/prover/src/utils/rpc.ts rename to packages/prover/src/utils/rpc_provider.ts index a566c2df913d..4e7a77b2ca8d 100644 --- a/packages/prover/src/utils/rpc.ts +++ b/packages/prover/src/utils/rpc_provider.ts @@ -23,7 +23,7 @@ import {isNullish} from "./validation.js"; export type Optional = Omit & {[P in keyof T]?: T[P] | undefined}; -export class ELRpc { +export class ELRpcProvider { private handler: ELRequestHandler; private logger: Logger; @@ -34,12 +34,23 @@ export class ELRpc { this.logger = logger; } + /** + * Request the EL RPC Provider + * + * @template K + * @template E + * @param {K} method - RPC Method + * @param {ELApiParams[K]} params - RPC Params + * @param {{raiseError?: E}} [opts] + * @return {*} {Promise : JsonRpcResponseWithResultPayload>} + * @memberof ELRpc + */ async request( method: K, params: ELApiParams[K], - opts: {raiseError: E} + opts?: {raiseError?: E} ): Promise : JsonRpcResponseWithResultPayload> { - const {raiseError} = opts; + const {raiseError} = opts ?? {raiseError: true}; const payload: JsonRpcRequest = {jsonrpc: "2.0", method, params, id: this.getRequestId()}; logRequest(payload, this.logger); diff --git a/packages/prover/src/utils/verification.ts b/packages/prover/src/utils/verification.ts index b168ea327e03..a468bf277eba 100644 --- a/packages/prover/src/utils/verification.ts +++ b/packages/prover/src/utils/verification.ts @@ -4,7 +4,7 @@ import {ELBlock, ELProof, HexString, JsonRpcRequest} from "../types.js"; import {bufferToHex} from "./conversion.js"; import {getELBlock, getELCode, getELProof} from "./execution.js"; import {isValidAccount, isValidBlock, isValidCodeHash, isValidStorageKeys} from "./validation.js"; -import {ELRpc} from "./rpc.js"; +import {ELRpcProvider} from "./rpc_provider.js"; type VerificationResult = {data: T; valid: true} | {valid: false; data?: undefined}; @@ -16,7 +16,7 @@ export async function verifyAccount({ block, }: { address: HexString; - rpc: ELRpc; + rpc: ELRpcProvider; proofProvider: ProofProvider; logger: Logger; block?: number | string; @@ -54,7 +54,7 @@ export async function verifyCode({ block, }: { address: HexString; - rpc: ELRpc; + rpc: ELRpcProvider; proofProvider: ProofProvider; logger: Logger; codeHash: HexString; @@ -81,7 +81,7 @@ export async function verifyBlock({ rpc, }: { payload: JsonRpcRequest<[block: string | number, hydrated: boolean]>; - rpc: ELRpc; + rpc: ELRpcProvider; proofProvider: ProofProvider; logger: Logger; }): Promise> { diff --git a/packages/prover/src/web3_provider.ts b/packages/prover/src/web3_provider.ts index 38dee22cedc7..b42c349d1017 100644 --- a/packages/prover/src/web3_provider.ts +++ b/packages/prover/src/web3_provider.ts @@ -1,41 +1,34 @@ -import {Logger} from "@lodestar/utils"; -import {getBrowserLogger} from "@lodestar/logger/browser"; import {LogLevel} from "@lodestar/logger"; -import { - EIP1193Provider, - EthersProvider, - RequestProvider, - SendAsyncProvider, - SendProvider, - VerifiedExecutionInitOptions, - Web3Provider, -} from "./interfaces.js"; +import {getBrowserLogger} from "@lodestar/logger/browser"; +import {Logger} from "@lodestar/utils"; +import {AnyWeb3Provider, ELRequestHandler, VerifiedExecutionInitOptions} from "./interfaces.js"; import {ProofProvider} from "./proof_provider/proof_provider.js"; -import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponseOrBatch} from "./types.js"; -import { - isEIP1193Provider, - isEthersProvider, - isRequestProvider, - isSendAsyncProvider, - isSendProvider, - isWeb3jsProvider, -} from "./utils/assertion.js"; +import {ELRpcProvider} from "./utils/rpc_provider.js"; +import {Web3ProviderInspector} from "./web3_provider_inspector.js"; import {processAndVerifyRequest} from "./utils/process.js"; -import {isBatchRequest} from "./utils/json_rpc.js"; -import {ELRpc} from "./utils/rpc.js"; -export type Web3ProviderTypeHandler = ( +export type Web3ProviderTypeHandler = ( provider: T, proofProvider: ProofProvider, logger: Logger -) => {provider: T; rpc: ELRpc}; +) => {provider: T; handler: ELRpcProvider["handler"]}; -export function createVerifiedExecutionProvider( - provider: T, - opts: VerifiedExecutionInitOptions -): {provider: T; proofProvider: ProofProvider} { +export function createVerifiedExecutionProvider< + T extends AnyWeb3Provider, + Mutate extends undefined | boolean = true, + Return = {provider: Mutate extends undefined | true ? T : ELRpcProvider; proofProvider: ProofProvider}, +>(provider: T, opts: VerifiedExecutionInitOptions): Return { const signal = opts.signal ?? new AbortController().signal; const logger = opts.logger ?? getBrowserLogger({level: opts.logLevel ?? LogLevel.info}); + const mutateProvider = opts.mutateProvider === undefined; + const customProviderTypes = opts.providerTypes ?? []; + + const providerInspector = Web3ProviderInspector.initWithDefault({logger}); + for (const providerType of customProviderTypes.reverse()) { + providerInspector.register(providerType, {index: 0}); + } + const providerType = providerInspector.detect(provider); + logger.debug(`Provider is detected as '${providerType.name}' provider.`); const proofProvider = ProofProvider.init({ ...opts, @@ -43,191 +36,23 @@ export function createVerifiedExecutionProvider( logger, }); - const handler = getProviderTypeHandler(provider, logger); - const {provider: newInstance, rpc} = handler(provider, proofProvider, logger); + const nonVerifiedHandler = providerType.handler(provider); + const nonVerifiedRpc = new ELRpcProvider(nonVerifiedHandler, logger); - rpc.verifyCompatibility().catch((err) => { + nonVerifiedRpc.verifyCompatibility().catch((err) => { logger.error(err); logger.error("Due to compatibility issues, verified execution may not work properly."); }); - return {provider: newInstance, proofProvider: proofProvider}; -} - -function handleSendProvider( - provider: SendProvider, - proofProvider: ProofProvider, - logger: Logger -): {provider: SendProvider; rpc: ELRpc} { - const send = provider.send.bind(provider); - const handler = (payload: JsonRpcRequestOrBatch): Promise => - new Promise((resolve, reject) => { - // web3 providers supports batch requests but don't have valid types - send(payload as JsonRpcRequest, (err, response) => { - if (err) { - reject(err); - } else { - resolve(response); - } - }); - }); - const rpc = new ELRpc(handler, logger); - - function newSend( - payload: JsonRpcRequestOrBatch, - callback: (err?: Error | null, response?: JsonRpcResponseOrBatch) => void - ): void { - processAndVerifyRequest({payload, rpc, proofProvider, logger}) - .then((response) => callback(undefined, response)) - .catch((err) => callback(err, undefined)); - } - - return {provider: Object.assign(provider, {send: newSend}), rpc}; -} - -function handleRequestProvider( - provider: RequestProvider, - proofProvider: ProofProvider, - logger: Logger -): {provider: RequestProvider; rpc: ELRpc} { - const request = provider.request.bind(provider); - const handler = (payload: JsonRpcRequestOrBatch): Promise => - new Promise((resolve, reject) => { - request(payload, (err, response) => { - if (err) { - reject(err); - } else { - resolve(response); - } - }); - }); - const rpc = new ELRpc(handler, logger); - - function newRequest( - payload: JsonRpcRequestOrBatch, - callback: (err?: Error | null, response?: JsonRpcResponseOrBatch) => void - ): void { - processAndVerifyRequest({payload, rpc, proofProvider, logger}) - .then((response) => callback(undefined, response)) - .catch((err) => callback(err, undefined)); - } - - return {provider: Object.assign(provider, {request: newRequest}), rpc}; -} - -function handleSendAsyncProvider( - provider: SendAsyncProvider, - proofProvider: ProofProvider, - logger: Logger -): {provider: SendAsyncProvider; rpc: ELRpc} { - const sendAsync = provider.sendAsync.bind(provider); - const handler = async (payload: JsonRpcRequestOrBatch): Promise => { - const response = await sendAsync(payload); - return response; + const verifiedHandler: ELRequestHandler = function newVerifiedHandler(payload) { + return processAndVerifyRequest({payload, rpc: nonVerifiedRpc, logger, proofProvider}); }; - const rpc = new ELRpc(handler, logger); - - async function newSendAsync(payload: JsonRpcRequestOrBatch): Promise { - return processAndVerifyRequest({payload, rpc, proofProvider, logger}); - } - - return {provider: Object.assign(provider, {sendAsync: newSendAsync}), rpc}; -} - -function handleEIP1193Provider( - provider: EIP1193Provider, - proofProvider: ProofProvider, - logger: Logger -): {provider: EIP1193Provider; rpc: ELRpc} { - const request = provider.request.bind(provider); - const handler = async (payload: JsonRpcRequestOrBatch): Promise => { - const response = await request(payload); - return response; - }; - const rpc = new ELRpc(handler, logger); - - async function newRequest(payload: JsonRpcRequestOrBatch): Promise { - return processAndVerifyRequest({payload, rpc, proofProvider, logger}); - } - - return {provider: Object.assign(provider, {request: newRequest}), rpc}; -} - -function handleEthersProvider( - provider: EthersProvider, - proofProvider: ProofProvider, - logger: Logger -): {provider: EthersProvider; rpc: ELRpc} { - const send = provider.send.bind(provider); - const handler = async (payload: JsonRpcRequestOrBatch): Promise => { - // Because ethers provider public interface does not support batch requests - // so we need to handle it manually - if (isBatchRequest(payload)) { - const responses = []; - for (const request of payload) { - responses.push(await send(request.method, request.params)); - } - return responses; - } - - return send(payload.method, payload.params); - }; - const rpc = new ELRpc(handler, logger); - - async function newSend(method: string, params: Array): Promise { - return processAndVerifyRequest({ - payload: {jsonrpc: "2.0", id: 0, method, params}, - rpc, - proofProvider, - logger, - }); - } - - return {provider: Object.assign(provider, {send: newSend}), rpc}; -} -/** - * - * - * @export - * @template T - * @param {T} provider - * @param {Logger} logger - * @return {*} {Web3ProviderTypeHandler} - */ -export function getProviderTypeHandler( - provider: T, - logger: Logger -): Web3ProviderTypeHandler { - if (isWeb3jsProvider(provider)) { - logger.debug("Provider is recognized as 'web3.js' provider."); - // EIP-1193 provider is fully compatible with web3.js#4x provider interface - return handleEIP1193Provider as unknown as Web3ProviderTypeHandler; - } - - if (isEthersProvider(provider)) { - logger.debug("Provider is recognized as 'ethers' provider."); - return handleEthersProvider as unknown as Web3ProviderTypeHandler; - } - - if (isEIP1193Provider(provider)) { - logger.debug("Provider is recognized as 'EIP1193' provider."); - return handleEIP1193Provider as unknown as Web3ProviderTypeHandler; - } - - if (isSendProvider(provider)) { - logger.debug("Provider is recognized as legacy provider with 'send' method."); - return handleSendProvider as unknown as Web3ProviderTypeHandler; - } - - if (isRequestProvider(provider)) { - logger.debug("Provider is recognized as legacy provider with 'request' method."); - return handleRequestProvider as unknown as Web3ProviderTypeHandler; - } - if (isSendAsyncProvider(provider)) { - logger.debug("Provider is recognized as legacy provider with 'sendAsync' method."); - return handleSendAsyncProvider as unknown as Web3ProviderTypeHandler; + if (mutateProvider) { + providerType.mutateProvider(provider, verifiedHandler); + return {provider, proofProvider} as Return; } - throw new Error("Unsupported provider type"); + // Verified RPC + return {provider: new ELRpcProvider(verifiedHandler, logger), proofProvider} as Return; } diff --git a/packages/prover/src/web3_provider_inspector.ts b/packages/prover/src/web3_provider_inspector.ts new file mode 100644 index 000000000000..c81847b64d61 --- /dev/null +++ b/packages/prover/src/web3_provider_inspector.ts @@ -0,0 +1,89 @@ +import {Logger} from "@lodestar/logger"; +import {AnyWeb3Provider, Web3ProviderType} from "./interfaces.js"; + +import web3jsProviderType from "./provider_types/web3_js_provider_type.js"; +import ethersProviderType from "./provider_types/ethers_provider_type.js"; +import eip1193ProviderType from "./provider_types/eip1193_provider_type.js"; +import legacyProviderType from "./provider_types/legacy_provider_type.js"; + +export class Web3ProviderInspector { + protected providerTypes: Web3ProviderType[] = []; + logger: Logger; + + protected constructor(opts: {logger: Logger}) { + this.logger = opts.logger; + } + + static initWithDefault(opts: {logger: Logger}): Web3ProviderInspector { + const inspector = new Web3ProviderInspector(opts); + inspector.register(web3jsProviderType, {index: 0}); + inspector.register(ethersProviderType, {index: 1}); + inspector.register(eip1193ProviderType, {index: 2}); + inspector.register(legacyProviderType, {index: 3}); + + return inspector; + } + + getProviderTypes(): Web3ProviderType[] { + // Destruct so user can not mutate the output + return [...this.providerTypes]; + } + + register(providerType: Web3ProviderType, opts?: {index?: number}): void { + // If user does not provider index, we will register the provider type to last + let index = opts?.index ?? this.providerTypes.length; + + // If index is larger, let's add type at the end + if (index > this.providerTypes.length) { + index = this.providerTypes.length; + } + + // If a lower index is provided let's add type at the start + if (index < 0) { + index = 0; + } + + if (this.providerTypes.map((p) => p.name).includes(providerType.name)) { + throw new Error(`Provider type '${providerType.name}' is already registered.`); + } + + // If some provider type is already register on that index, we will make space for new + if (this.providerTypes.at(index)) { + this.logger.debug( + `A provider type '${this.providerTypes[index].name}' already existed at index '${index}', now moved down.` + ); + this.providerTypes.splice(index, 0, providerType); + } + + this.logger.debug(`Registered provider type "${providerType.name}" at index ${index}`); + this.providerTypes[index] = providerType; + } + + unregister(indexOrName: string | number): void { + if (typeof indexOrName === "number") { + if (indexOrName > this.providerTypes.length || indexOrName < 0) { + throw new Error(`Provider type at index '${indexOrName}' is not registered.`); + } + this.providerTypes.splice(indexOrName, 1); + return; + } + + const index = this.providerTypes.findIndex((p) => p.name == indexOrName); + if (index < 0) { + throw Error(`Provider type '${indexOrName}' is not registered.`); + } + this.providerTypes.splice(index, 1); + } + + detect(provider: AnyWeb3Provider): Web3ProviderType { + for (const providerType of Object.values(this.providerTypes)) { + if (providerType.matched(provider)) { + return providerType; + } + } + + throw new Error( + `Given provider could not be detected of any type. Supported types are ${Object.keys(this.providerTypes).join()}` + ); + } +} diff --git a/packages/prover/src/web3_proxy.ts b/packages/prover/src/web3_proxy.ts index 6aa44b314953..273508852adf 100644 --- a/packages/prover/src/web3_proxy.ts +++ b/packages/prover/src/web3_proxy.ts @@ -10,9 +10,9 @@ import {JsonRpcRequestOrBatch, JsonRpcRequestPayload, JsonRpcResponseOrBatch} fr import {getResponseForRequest, isBatchRequest} from "./utils/json_rpc.js"; import {fetchRequestPayload, fetchResponseBody} from "./utils/req_resp.js"; import {processAndVerifyRequest} from "./utils/process.js"; -import {ELRpc} from "./utils/rpc.js"; +import {ELRpcProvider} from "./utils/rpc_provider.js"; -export type VerifiedProxyOptions = VerifiedExecutionInitOptions & { +export type VerifiedProxyOptions = Exclude, "mutateProvider" | "providerTypes"> & { executionRpcUrl: string; requestTimeout: number; }; @@ -86,7 +86,7 @@ export function createVerifiedExecutionProxy(opts: VerifiedProxyOptions): { }); let proxyServerListeningAddress: {host: string; port: number} | undefined; - const rpc = new ELRpc( + const rpc = new ELRpcProvider( createHttpHandler({ signal, info: () => { diff --git a/packages/prover/test/e2e/web3_provider.test.ts b/packages/prover/test/e2e/web3_provider.test.ts index ad00ae71b9fc..3d670d7ed412 100644 --- a/packages/prover/test/e2e/web3_provider.test.ts +++ b/packages/prover/test/e2e/web3_provider.test.ts @@ -43,5 +43,22 @@ describe("web3_provider", function () { await expect(provider.send("eth_getProof", [accounts[0].address, [], "latest"])).resolves.toBeDefined(); }); }); + + describe("ELRpc", () => { + it("should connect to the network and and call verified methods only", async () => { + const nonVerifiedProvider = new Web3.providers.HttpProvider(rpcUrl); + const {provider: verifiedProvider} = createVerifiedExecutionProvider(nonVerifiedProvider, { + transport: LCTransport.Rest, + urls: [beaconUrl], + config, + mutateProvider: false, + }); + + const web3 = new Web3(nonVerifiedProvider); + const accounts = await web3.eth.getAccounts(); + + await expect(verifiedProvider.request("eth_getBalance", [accounts[0], "latest"])).resolves.toBeDefined(); + }); + }); }); }); diff --git a/packages/prover/test/unit/provider_types/ethers_provider_type.test.ts b/packages/prover/test/unit/provider_types/ethers_provider_type.test.ts new file mode 100644 index 000000000000..c24252d9548f --- /dev/null +++ b/packages/prover/test/unit/provider_types/ethers_provider_type.test.ts @@ -0,0 +1,16 @@ +import {describe, it, expect} from "vitest"; +import {ethers} from "ethers"; +import {Web3} from "web3"; +import ethersProviderType from "../../../src/provider_types/ethers_provider_type.js"; + +describe("matched", () => { + it("should return false if provider is not ethers provider", () => { + const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(ethersProviderType.matched(provider)).toBe(false); + }); + + it("should return true if provider is ethers provider", () => { + const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(ethersProviderType.matched(provider)).toBe(true); + }); +}); diff --git a/packages/prover/test/unit/provider_types/legacy_provider_type.test.ts b/packages/prover/test/unit/provider_types/legacy_provider_type.test.ts new file mode 100644 index 000000000000..37ffc18e58ab --- /dev/null +++ b/packages/prover/test/unit/provider_types/legacy_provider_type.test.ts @@ -0,0 +1,27 @@ +import {describe, it, expect} from "vitest"; +import {ethers} from "ethers"; +import {Web3} from "web3"; +import legacyProviderType from "../../../src/provider_types/legacy_provider_type.js"; + +describe("send provider", () => { + describe("matched", () => { + it("should return true if provider is SendProvider", () => { + const provider = { + send: (_payload: any, _cb: () => void) => { + // Do nothing; + }, + }; + expect(legacyProviderType.matched(provider)).toBe(true); + }); + + it("should return false for ethers provider", () => { + const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(legacyProviderType.matched(provider)).toBe(false); + }); + + it("should return false for web3 provider", () => { + const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(legacyProviderType.matched(provider)).toBe(false); + }); + }); +}); diff --git a/packages/prover/test/unit/provider_types/web3js_provider_type.test.ts b/packages/prover/test/unit/provider_types/web3js_provider_type.test.ts new file mode 100644 index 000000000000..54da395bca25 --- /dev/null +++ b/packages/prover/test/unit/provider_types/web3js_provider_type.test.ts @@ -0,0 +1,16 @@ +import {describe, it, expect} from "vitest"; +import {ethers} from "ethers"; +import {Web3} from "web3"; +import web3jsProviderType from "../../../src/provider_types/web3_js_provider_type.js"; + +describe("matched", () => { + it("should return true if provider is web3.js provider", () => { + const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(web3jsProviderType.matched(provider)).toBe(true); + }); + + it("should return false if provider is not web3.js provider", () => { + const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); + expect(web3jsProviderType.matched(provider)).toBe(false); + }); +}); diff --git a/packages/prover/test/unit/utils/assertion.test.ts b/packages/prover/test/unit/utils/assertion.test.ts deleted file mode 100644 index 3ea712bab1f1..000000000000 --- a/packages/prover/test/unit/utils/assertion.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {describe, it, expect} from "vitest"; -import {ethers} from "ethers"; -import {Web3} from "web3"; -import {isSendProvider, isWeb3jsProvider, isEthersProvider} from "../../../src/utils/assertion.js"; - -describe("utils/assertion", () => { - describe("isSendProvider", () => { - it("should return true if provider is SendProvider", () => { - const provider = { - send: (_payload: any, _cb: () => void) => { - // Do nothing; - }, - }; - expect(isSendProvider(provider)).toBe(true); - }); - - it("should return false for ethers provider", () => { - const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isSendProvider(provider)).toBe(false); - }); - - it("should return false for web3 provider", () => { - const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isSendProvider(provider)).toBe(false); - }); - }); - - describe("isWeb3jsProvider", () => { - it("should return true if provider is web3.js provider", () => { - const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isWeb3jsProvider(provider)).toBe(true); - }); - - it("should return false if provider is not web3.js provider", () => { - const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isWeb3jsProvider(provider)).toBe(false); - }); - }); - - describe("isEthersProvider", () => { - it("should return false if provider is not ethers provider", () => { - const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isEthersProvider(provider)).toBe(false); - }); - - it("should return true if provider is ethers provider", () => { - const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"); - expect(isEthersProvider(provider)).toBe(true); - }); - }); -}); diff --git a/packages/prover/test/unit/web3_provider.node.test.ts b/packages/prover/test/unit/web3_provider.node.test.ts index a83fbde4d858..d1f281175b56 100644 --- a/packages/prover/test/unit/web3_provider.node.test.ts +++ b/packages/prover/test/unit/web3_provider.node.test.ts @@ -1,8 +1,11 @@ import {describe, it, expect, afterEach, vi} from "vitest"; import {Web3} from "web3"; import {ethers} from "ethers"; -import {createVerifiedExecutionProvider, ProofProvider, LCTransport} from "@lodestar/prover/browser"; -import {ELRpc} from "../../src/utils/rpc.js"; +import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; +import {ELRpcProvider} from "../../src/utils/rpc_provider.js"; +import {ProofProvider} from "../../src/proof_provider/proof_provider.js"; +import {LCTransport, Web3ProviderType} from "../../src/interfaces.js"; +import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse} from "../../src/types.js"; describe("web3_provider", () => { afterEach(() => { @@ -13,7 +16,7 @@ describe("web3_provider", () => { describe("web3", () => { it("should create a verified execution provider for the web3 provider", () => { // Don't invoke network in unit tests - vi.spyOn(ELRpc.prototype, "verifyCompatibility").mockResolvedValue(); + vi.spyOn(ELRpcProvider.prototype, "verifyCompatibility").mockResolvedValue(); const {provider, proofProvider} = createVerifiedExecutionProvider( new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"), @@ -32,7 +35,7 @@ describe("web3_provider", () => { describe("ethers", () => { it("should create a verified execution provider for the ethers provider", () => { // Don't invoke network in unit tests - vi.spyOn(ELRpc.prototype, "verifyCompatibility").mockResolvedValue(); + vi.spyOn(ELRpcProvider.prototype, "verifyCompatibility").mockResolvedValue(); const {provider, proofProvider} = createVerifiedExecutionProvider( new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"), @@ -47,5 +50,75 @@ describe("web3_provider", () => { expect(proofProvider).toBeInstanceOf(ProofProvider); }); }); + + describe("non-mutated provider", () => { + it("should create an ELRpc object from the web3 provider when non-mutate options provided", () => { + const {provider, proofProvider} = createVerifiedExecutionProvider( + new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"), + { + transport: LCTransport.Rest, + urls: ["https://lodestar-sepolia.chainsafe.io"], + network: "sepolia", + mutateProvider: false, + } + ); + + expect(provider).toBeInstanceOf(ELRpcProvider); + expect(proofProvider).toBeInstanceOf(ProofProvider); + }); + }); + + describe("custom provider type", () => { + it("should be able to detect and use the custom provider", async () => { + type CustomProvider = {myrequest: (payload: JsonRpcRequest) => Promise}; + + const customProviderType: Web3ProviderType = { + name: "custom", + matched(provider): provider is CustomProvider { + return true; + }, + handler(provider) { + const handler = provider.myrequest.bind(provider); + + return function newHandler(payload: JsonRpcRequestOrBatch) { + if (Array.isArray(payload)) { + return Promise.all(payload.map((p) => handler(p))); + } + + return handler(payload); + }; + }, + mutateProvider(_provider): void { + // That's a deprecated behavior we don't want to test it + }, + }; + + const customProvider = { + myrequest: vi.fn().mockResolvedValue({result: "my-custom-result"}), + }; + + // Don't invoke network in unit tests + vi.spyOn(ELRpcProvider.prototype, "verifyCompatibility").mockResolvedValue(); + const {provider} = createVerifiedExecutionProvider(customProvider, { + transport: LCTransport.Rest, + urls: ["https://lodestar-sepolia.chainsafe.io"], + network: "sepolia", + mutateProvider: false, + providerTypes: [customProviderType], + }); + + const result = await provider.request("eth_getProof", ["nazar", [], ""]); + + expect(result).toEqual({result: "my-custom-result"}); + expect(customProvider.myrequest).toBeCalledTimes(1); + + expect(customProvider.myrequest).toHaveBeenCalledWith({ + jsonrpc: "2.0", + id: "1", + method: "eth_getProof", + params: ["nazar", [], ""], + }); + }); + }); }); }); diff --git a/packages/prover/test/unit/web3_provider_inspector.test.ts b/packages/prover/test/unit/web3_provider_inspector.test.ts new file mode 100644 index 000000000000..95df8a0d760e --- /dev/null +++ b/packages/prover/test/unit/web3_provider_inspector.test.ts @@ -0,0 +1,85 @@ +import {describe, it, beforeEach, expect} from "vitest"; +import {getEnvLogger} from "@lodestar/logger/env"; +import {LogLevel} from "@lodestar/logger"; +import {Web3ProviderInspector} from "../../src/web3_provider_inspector.js"; +import {AnyWeb3Provider, Web3ProviderType} from "../../src/interfaces.js"; +import web3JsProviderType from "../../src/provider_types/web3_js_provider_type.js"; + +describe("Web3ProviderInspector", () => { + let inspector: Web3ProviderInspector; + let customType: Web3ProviderType; + + beforeEach(() => { + customType = { + ...web3JsProviderType, + name: "custom", + }; + inspector = Web3ProviderInspector.initWithDefault({logger: getEnvLogger({level: LogLevel.debug})}); + }); + + it("should have pre-registered types", () => { + expect(inspector.getProviderTypes()).toHaveLength(4); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual(["web3js", "ethers", "eip1193", "legacy"]); + }); + + describe("register", () => { + it("should raise error if try to register pre-existing type", () => { + expect(() => inspector.register(web3JsProviderType)).toThrowError( + "Provider type 'web3js' is already registered." + ); + }); + + it("should register at max index if provided a large value", () => { + expect(() => inspector.register(customType, {index: 10})).not.toThrowError(); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual([ + "web3js", + "ethers", + "eip1193", + "legacy", + "custom", + ]); + }); + + it("should register at start index if provided a lower value", () => { + expect(() => inspector.register(customType, {index: -1})).not.toThrowError(); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual([ + "custom", + "web3js", + "ethers", + "eip1193", + "legacy", + ]); + }); + + it("should make space for existing index", () => { + expect(() => inspector.register(customType, {index: 2})).not.toThrowError(); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual([ + "web3js", + "ethers", + "custom", + "eip1193", + "legacy", + ]); + }); + }); + + describe("unregister", () => { + it("should unregister provider type given the name", () => { + inspector.unregister("ethers"); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual(["web3js", "eip1193", "legacy"]); + }); + + it("should raise error if given name is not registered", () => { + expect(() => inspector.unregister("custom")).toThrowError("Provider type 'custom' is not registered."); + }); + + it("should unregister provider type given the index", () => { + inspector.unregister(2); + expect(inspector.getProviderTypes().map((t) => t.name)).toEqual(["web3js", "ethers", "legacy"]); + }); + + it("should raise error if given index not available", () => { + expect(() => inspector.unregister(10)).toThrowError("Provider type at index '10' is not registered."); + }); + }); +}); diff --git a/packages/reqresp/README.md b/packages/reqresp/README.md index 8298a15187ad..dbfbf304c541 100644 --- a/packages/reqresp/README.md +++ b/packages/reqresp/README.md @@ -3,7 +3,7 @@ [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) [![ETH Beacon APIs Spec v2.1.0](https://img.shields.io/badge/ETH%20beacon--APIs-2.1.0-blue)](https://github.com/ethereum/beacon-APIs/releases/tag/v2.1.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 1db19c418cdb..6e671c3ade82 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -53,10 +53,10 @@ }, "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", - "@libp2p/interface": "^1.1.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@libp2p/interface": "^1.3.0", + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/utils": "^1.19.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -65,12 +65,12 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.18.1", - "@lodestar/types": "^1.18.1", - "libp2p": "1.1.1" + "@lodestar/logger": "^1.19.0", + "@lodestar/types": "^1.19.0", + "libp2p": "1.4.3" }, "peerDependencies": { - "libp2p": "~1.1.1" + "libp2p": "~1.4.3" }, "keywords": [ "ethereum", diff --git a/packages/reqresp/src/encoders/responseEncode.ts b/packages/reqresp/src/encoders/responseEncode.ts index 3e2d875685e8..c5320ffc1ce9 100644 --- a/packages/reqresp/src/encoders/responseEncode.ts +++ b/packages/reqresp/src/encoders/responseEncode.ts @@ -3,6 +3,8 @@ import {encodeErrorMessage} from "../utils/index.js"; import {ContextBytesType, ContextBytesFactory, MixedProtocol, Protocol, ResponseOutgoing} from "../types.js"; import {RespStatus, RpcResponseStatusError} from "../interface.js"; +const SUCCESS_BUFFER = Buffer.from([RespStatus.SUCCESS]); + /** * Yields byte chunks for a `` with a zero response code `` * ```bnf @@ -24,7 +26,7 @@ export function responseEncodeSuccess( cbs.onChunk(chunkIndex++); // - yield Buffer.from([RespStatus.SUCCESS]); + yield SUCCESS_BUFFER; // - from altair const contextBytes = getContextBytes(protocol.contextBytes, chunk); diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/encode.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/encode.ts index 930aa242766d..f4559b91f3fe 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/encode.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/encode.ts @@ -15,7 +15,8 @@ export const writeSszSnappyPayload = encodeSszSnappy as (bytes: Uint8Array) => A */ export async function* encodeSszSnappy(bytes: Buffer): AsyncGenerator { // MUST encode the length of the raw SSZ bytes, encoded as an unsigned protobuf varint - yield Buffer.from(varintEncode(bytes.length)); + const varint = varintEncode(bytes.length); + yield Buffer.from(varint.buffer, varint.byteOffset, varint.byteLength); // By first computing and writing the SSZ byte length, the SSZ encoder can then directly // write the chunk contents to the stream. Snappy writer compresses frame by frame diff --git a/packages/reqresp/src/utils/errorMessage.ts b/packages/reqresp/src/utils/errorMessage.ts index c9ca6505d282..3af32a8f5c5c 100644 --- a/packages/reqresp/src/utils/errorMessage.ts +++ b/packages/reqresp/src/utils/errorMessage.ts @@ -1,4 +1,4 @@ -import {encodeSszSnappy} from "../encodingStrategies/sszSnappy/encode.js"; +import {writeSszSnappyPayload} from "../encodingStrategies/sszSnappy/encode.js"; import {Encoding} from "../types.js"; // ErrorMessage schema: @@ -17,11 +17,11 @@ import {Encoding} from "../types.js"; */ export async function* encodeErrorMessage(errorMessage: string, encoding: Encoding): AsyncGenerator { const encoder = new TextEncoder(); - const bytes = Buffer.from(encoder.encode(errorMessage).slice(0, 256)); + const bytes = encoder.encode(errorMessage).slice(0, 256); switch (encoding) { case Encoding.SSZ_SNAPPY: - yield* encodeSszSnappy(bytes); + yield* writeSszSnappyPayload(bytes); } } diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index fef33c0f6e31..f092a26fc8b0 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/spec-test-util", - "version": "1.18.1", + "version": "1.19.0", "description": "Spec test suite generator from yaml test files", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "blockchain" ], "dependencies": { - "@lodestar/utils": "^1.18.1", + "@lodestar/utils": "^1.19.0", "axios": "^1.3.4", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", diff --git a/packages/state-transition/README.md b/packages/state-transition/README.md index b8720c725449..e2aa5e2d8bfd 100644 --- a/packages/state-transition/README.md +++ b/packages/state-transition/README.md @@ -2,7 +2,7 @@ [![npm](https://img.shields.io/npm/v/@lodestar/state-transition)](https://www.npmjs.com/package/@lodestar/state-transition) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) ![Node Version](https://img.shields.io/badge/8.x-green) diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index c2ab59b045ad..76b7f52325a3 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -60,19 +60,15 @@ "dependencies": { "@chainsafe/as-sha256": "^0.4.1", "@chainsafe/bls": "7.1.3", - "@chainsafe/blst": "^0.2.10", + "@chainsafe/blst": "^0.2.11", "@chainsafe/persistent-merkle-tree": "^0.7.1", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.15.1", - "@lodestar/config": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", - "bigint-buffer": "^1.1.5", - "buffer-xor": "^2.0.2" - }, - "devDependencies": { - "@types/buffer-xor": "^2.0.0" + "@lodestar/config": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", + "bigint-buffer": "^1.1.5" }, "keywords": [ "ethereum", diff --git a/packages/state-transition/src/block/processRandao.ts b/packages/state-transition/src/block/processRandao.ts index cf9ea193b944..effeb34390cb 100644 --- a/packages/state-transition/src/block/processRandao.ts +++ b/packages/state-transition/src/block/processRandao.ts @@ -1,4 +1,3 @@ -import xor from "buffer-xor"; import {digest} from "@chainsafe/as-sha256"; import {allForks} from "@lodestar/types"; import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; @@ -28,6 +27,14 @@ export function processRandao( } // mix in RANDAO reveal - const randaoMix = xor(Buffer.from(getRandaoMix(state, epoch)), Buffer.from(digest(randaoReveal))); + const randaoMix = xor(getRandaoMix(state, epoch), digest(randaoReveal)); state.randaoMixes.set(epoch % EPOCHS_PER_HISTORICAL_VECTOR, randaoMix); } + +function xor(a: Uint8Array, b: Uint8Array): Uint8Array { + const length = Math.min(a.length, b.length); + for (let i = 0; i < length; i++) { + a[i] = a[i] ^ b[i]; + } + return a; +} diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 64a3f4f23c8f..fdc343ff4ec7 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -23,7 +23,7 @@ function toMemoryEfficientHexStr(hex: Uint8Array | string): string { return hex; } - return Buffer.from(hex).toString("hex"); + return Buffer.from(hex.buffer, hex.byteOffset, hex.byteLength).toString("hex"); } export class PubkeyIndexMap { diff --git a/packages/state-transition/src/util/shuffle.ts b/packages/state-transition/src/util/shuffle.ts index 07457c5975d0..39137bca69d0 100644 --- a/packages/state-transition/src/util/shuffle.ts +++ b/packages/state-transition/src/util/shuffle.ts @@ -90,6 +90,8 @@ function innerShuffleList(input: Shuffleable, seed: Bytes32, dir: boolean): void const listSize = input.length >>> 0; // check if list size fits in uint32 assert.equal(listSize, input.length, "input length does not fit uint32"); + // check that the seed is 32 bytes + assert.lte(seed.length, _SHUFFLE_H_SEED_SIZE, `seed length is not lte ${_SHUFFLE_H_SEED_SIZE} bytes`); const buf = Buffer.alloc(_SHUFFLE_H_TOTAL_SIZE); let r = 0; @@ -100,8 +102,7 @@ function innerShuffleList(input: Shuffleable, seed: Bytes32, dir: boolean): void } // Seed is always the first 32 bytes of the hash input, we never have to change this part of the buffer. - const _seed = seed; - Buffer.from(_seed).copy(buf, 0, 0, _SHUFFLE_H_SEED_SIZE); + buf.set(seed, 0); // initial values here are not used: overwritten first within the inner for loop. let source = seed; // just setting it to a Bytes32 @@ -114,8 +115,8 @@ function innerShuffleList(input: Shuffleable, seed: Bytes32, dir: boolean): void buf[_SHUFFLE_H_SEED_SIZE] = r; // Seed is already in place, now just hash the correct part of the buffer, and take a uint64 from it, // and modulo it to get a pivot within range. - const h = digest(buf.slice(0, _SHUFFLE_H_PIVOT_VIEW_SIZE)); - const pivot = Number(bytesToBigInt(h.slice(0, 8)) % BigInt(listSize)) >>> 0; + const h = digest(buf.subarray(0, _SHUFFLE_H_PIVOT_VIEW_SIZE)); + const pivot = Number(bytesToBigInt(h.subarray(0, 8)) % BigInt(listSize)) >>> 0; // Split up the for-loop in two: // 1. Handle the part from 0 (incl) to pivot (incl). This is mirrored around (pivot / 2) diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index bfb7d13c2c25..1a39f4d6c7ca 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@lodestar/test-utils", "private": true, - "version": "1.18.1", + "version": "1.19.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "dependencies": { "@chainsafe/bls": "7.1.3", "@chainsafe/bls-keystore": "^3.0.1", - "@lodestar/params": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/params": "^1.19.0", + "@lodestar/utils": "^1.19.0", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/README.md b/packages/types/README.md index d21815072466..749f93321d39 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -2,9 +2,9 @@ [![npm](https://img.shields.io/npm/v/@lodestar/types)](https://www.npmjs.com/package/@lodestar/types) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/types/package.json b/packages/types/package.json index 7c2fecaf7056..b892e6f0285a 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": { ".": { @@ -74,7 +74,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.15.1", - "@lodestar/params": "^1.18.1", + "@lodestar/params": "^1.19.0", "ethereum-cryptography": "^2.0.0" }, "keywords": [ diff --git a/packages/types/src/allForks/index.ts b/packages/types/src/allForks/index.ts index 7856cd729620..104de77d50c3 100644 --- a/packages/types/src/allForks/index.ts +++ b/packages/types/src/allForks/index.ts @@ -1,3 +1,7 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; + +// We have to use import->export because of the limitation in `@microsoft/api-extractor` +// which is used to bundle the package types +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/altair/index.ts b/packages/types/src/altair/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/altair/index.ts +++ b/packages/types/src/altair/index.ts @@ -1,3 +1,4 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/bellatrix/index.ts b/packages/types/src/bellatrix/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/bellatrix/index.ts +++ b/packages/types/src/bellatrix/index.ts @@ -1,3 +1,4 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/capella/index.ts b/packages/types/src/capella/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/capella/index.ts +++ b/packages/types/src/capella/index.ts @@ -1,3 +1,4 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/deneb/index.ts b/packages/types/src/deneb/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/deneb/index.ts +++ b/packages/types/src/deneb/index.ts @@ -1,3 +1,4 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 6931271aaa29..bfd0f6abb6f9 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,5 +1,6 @@ export * from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ssz from "./sszTypes.js"; +export {ssz}; // Typeguards export * from "./utils/typeguards.js"; // String type diff --git a/packages/types/src/phase0/index.ts b/packages/types/src/phase0/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/phase0/index.ts +++ b/packages/types/src/phase0/index.ts @@ -1,3 +1,4 @@ export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/types/src/primitive/index.ts b/packages/types/src/primitive/index.ts index 2953a04f16ab..b68df6795375 100644 --- a/packages/types/src/primitive/index.ts +++ b/packages/types/src/primitive/index.ts @@ -1,2 +1,3 @@ -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +import * as ssz from "./sszTypes.js"; +export {ts, ssz}; diff --git a/packages/utils/package.json b/packages/utils/package.json index 99172fdefc19..a0c46bb4994d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.18.1", + "version": "1.19.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/utils/src/verifyMerkleBranch.ts b/packages/utils/src/verifyMerkleBranch.ts index e109813dd29e..7bb090da06e4 100644 --- a/packages/utils/src/verifyMerkleBranch.ts +++ b/packages/utils/src/verifyMerkleBranch.ts @@ -23,5 +23,5 @@ export function verifyMerkleBranch( value = digest64(Buffer.concat([value, proof[i]])); } } - return Buffer.from(value).equals(root); + return Buffer.from(value.buffer, value.byteOffset, value.byteLength).equals(root); } diff --git a/packages/validator/README.md b/packages/validator/README.md index b075c2f293f4..b29972acf8ac 100644 --- a/packages/validator/README.md +++ b/packages/validator/README.md @@ -1,9 +1,9 @@ # Lodestar Validator [![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord&logo=discord)](https://discord.gg/aMxzVcr) -[![Eth Consensus Spec v1.1.10](https://img.shields.io/badge/ETH%20consensus--spec-1.1.10-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.1.10) +[![Eth Consensus Spec v1.4.0](https://img.shields.io/badge/ETH%20consensus--spec-1.4.0-blue)](https://github.com/ethereum/consensus-specs/releases/tag/v1.4.0) ![ES Version](https://img.shields.io/badge/ES-2021-yellow) -![Node Version](https://img.shields.io/badge/node-20.x-green) +![Node Version](https://img.shields.io/badge/node-22.x-green) > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project diff --git a/packages/validator/package.json b/packages/validator/package.json index c297b50a484f..7bd1cdae0ac7 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.18.1", + "version": "1.19.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -47,17 +47,17 @@ "dependencies": { "@chainsafe/bls": "7.1.3", "@chainsafe/ssz": "^0.15.1", - "@lodestar/api": "^1.18.1", - "@lodestar/config": "^1.18.1", - "@lodestar/db": "^1.18.1", - "@lodestar/params": "^1.18.1", - "@lodestar/state-transition": "^1.18.1", - "@lodestar/types": "^1.18.1", - "@lodestar/utils": "^1.18.1", + "@lodestar/api": "^1.19.0", + "@lodestar/config": "^1.19.0", + "@lodestar/db": "^1.19.0", + "@lodestar/params": "^1.19.0", + "@lodestar/state-transition": "^1.19.0", + "@lodestar/types": "^1.19.0", + "@lodestar/utils": "^1.19.0", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.18.1", + "@lodestar/test-utils": "^1.19.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } diff --git a/packages/validator/src/repositories/metaDataRepository.ts b/packages/validator/src/repositories/metaDataRepository.ts index c7824094741d..0ba1565a6651 100644 --- a/packages/validator/src/repositories/metaDataRepository.ts +++ b/packages/validator/src/repositories/metaDataRepository.ts @@ -25,7 +25,7 @@ export class MetaDataRepository { } async setGenesisValidatorsRoot(genesisValidatorsRoot: Root): Promise { - await this.db.put(this.encodeKey(GENESIS_VALIDATORS_ROOT), Buffer.from(genesisValidatorsRoot), this.dbReqOpts); + await this.db.put(this.encodeKey(GENESIS_VALIDATORS_ROOT), genesisValidatorsRoot, this.dbReqOpts); } async getGenesisTime(): Promise { @@ -34,7 +34,7 @@ export class MetaDataRepository { } async setGenesisTime(genesisTime: UintNum64): Promise { - await this.db.put(this.encodeKey(GENESIS_TIME), Buffer.from(ssz.UintNum64.serialize(genesisTime)), this.dbReqOpts); + await this.db.put(this.encodeKey(GENESIS_TIME), ssz.UintNum64.serialize(genesisTime), this.dbReqOpts); } private encodeKey(key: Uint8Array): Uint8Array { diff --git a/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts b/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts index 7606d31338c4..61c13bb17ce2 100644 --- a/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts +++ b/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts @@ -50,7 +50,7 @@ export class AttestationByTargetRepository { await this.db.batchPut( atts.map((att) => ({ key: this.encodeKey(pubkey, att.targetEpoch), - value: Buffer.from(this.type.serialize(att)), + value: this.type.serialize(att), })), this.dbReqOpts ); @@ -62,7 +62,7 @@ export class AttestationByTargetRepository { } private encodeKey(pubkey: BLSPubkey, targetEpoch: Epoch): Uint8Array { - return encodeKey(this.bucket, Buffer.concat([Buffer.from(pubkey), intToBytes(BigInt(targetEpoch), uintLen, "be")])); + return encodeKey(this.bucket, Buffer.concat([pubkey, intToBytes(BigInt(targetEpoch), uintLen, "be")])); } private decodeKey(key: Uint8Array): {pubkey: BLSPubkey; targetEpoch: Epoch} { diff --git a/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts b/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts index d45814e6648b..84a4e7032a70 100644 --- a/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts +++ b/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts @@ -35,10 +35,10 @@ export class AttestationLowerBoundRepository { } async set(pubkey: BLSPubkey, value: SlashingProtectionLowerBound): Promise { - await this.db.put(this.encodeKey(pubkey), Buffer.from(this.type.serialize(value)), this.dbReqOpts); + await this.db.put(this.encodeKey(pubkey), this.type.serialize(value), this.dbReqOpts); } private encodeKey(pubkey: BLSPubkey): Uint8Array { - return encodeKey(this.bucket, Buffer.from(pubkey)); + return encodeKey(this.bucket, pubkey); } } diff --git a/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts b/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts index 25b2fee7e8e5..eb1ae092cf3f 100644 --- a/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts +++ b/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts @@ -54,7 +54,7 @@ export class BlockBySlotRepository { await this.db.batchPut( blocks.map((block) => ({ key: this.encodeKey(pubkey, block.slot), - value: Buffer.from(this.type.serialize(block)), + value: this.type.serialize(block), })), this.dbReqOpts ); @@ -66,7 +66,7 @@ export class BlockBySlotRepository { } private encodeKey(pubkey: BLSPubkey, slot: Slot): Uint8Array { - return encodeKey(this.bucket, Buffer.concat([Buffer.from(pubkey), intToBytes(BigInt(slot), uintLen, "be")])); + return encodeKey(this.bucket, Buffer.concat([pubkey, intToBytes(BigInt(slot), uintLen, "be")])); } private decodeKey(key: Uint8Array): {pubkey: BLSPubkey; slot: Slot} { diff --git a/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts b/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts index db8345a90cc2..45315bf95b03 100644 --- a/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts +++ b/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts @@ -45,13 +45,13 @@ class SpanDistanceRepository { await this.db.batchPut( values.map((value) => ({ key: this.encodeKey(pubkey, value.source), - value: Buffer.from(this.type.serialize(value.distance)), + value: this.type.serialize(value.distance), })), this.dbReqOpts ); } private encodeKey(pubkey: BLSPubkey, epoch: Epoch): Uint8Array { - return encodeKey(this.bucket, Buffer.concat([Buffer.from(pubkey), intToBytes(BigInt(epoch), 8, "be")])); + return encodeKey(this.bucket, Buffer.concat([pubkey, intToBytes(BigInt(epoch), 8, "be")])); } } diff --git a/scripts/prepare-docs.sh b/scripts/prepare-docs.sh index 78b508bf5f29..8b52d7217d45 100755 --- a/scripts/prepare-docs.sh +++ b/scripts/prepare-docs.sh @@ -17,4 +17,3 @@ cp -r packages/prover/README.md $DOCS_DIR/pages/lightclient-prover/prover.md # Copy visual assets rm -rf $DOCS_DIR/pages/assets $DOCS_DIR/pages/images cp -r $ASSETS_DIR $DOCS_DIR/pages/assets -cp -r $DOCS_DIR/images $DOCS_DIR/pages/images diff --git a/scripts/vite/plugins/blsBrowserPlugin.ts b/scripts/vite/plugins/blsBrowserPlugin.ts new file mode 100644 index 000000000000..88c850f3fd1b --- /dev/null +++ b/scripts/vite/plugins/blsBrowserPlugin.ts @@ -0,0 +1,31 @@ +import path from "node:path"; +import {UserConfig, ConfigEnv, Plugin} from "vite"; +const __dirname = new URL(".", import.meta.url).pathname; +const polyfillsDir = path.join(__dirname, "../polyfills"); + +const emptyModulePath = path.join(__dirname, "../polyfills/emptyModule.js"); + +export function blsBrowserPlugin(): Plugin { + return { + name: "blsBrowserPlugin", + config(_config: UserConfig, _env: ConfigEnv) { + return { + optimizeDeps: { + force: true, + }, + resolve: { + alias: { + "@chainsafe/bls/types": "@chainsafe/bls/types", + "@chainsafe/bls": "@chainsafe/bls/herumi", + // This is just used to generate `privateKey` which is not used in the browser. + "@chainsafe/bls-keygen": path.join(polyfillsDir, "bls-keygen.js"), + "@chainsafe/blst": emptyModulePath, + "@chainsafe/bls-hd-key": emptyModulePath, + crypto: emptyModulePath, + "node:crypto": emptyModulePath, + }, + }, + }; + }, + }; +} diff --git a/scripts/vitest/plugins/buildTargetPlugin.ts b/scripts/vite/plugins/buildTargetPlugin.ts similarity index 100% rename from scripts/vitest/plugins/buildTargetPlugin.ts rename to scripts/vite/plugins/buildTargetPlugin.ts diff --git a/scripts/vite/polyfills/bls-keygen.js b/scripts/vite/polyfills/bls-keygen.js new file mode 100644 index 000000000000..779e200eb942 --- /dev/null +++ b/scripts/vite/polyfills/bls-keygen.js @@ -0,0 +1 @@ +export function generateRandomSecretKey() {} diff --git a/scripts/vite/polyfills/emptyModule.js b/scripts/vite/polyfills/emptyModule.js new file mode 100644 index 000000000000..ff8b4c56321a --- /dev/null +++ b/scripts/vite/polyfills/emptyModule.js @@ -0,0 +1 @@ +export default {}; diff --git a/scripts/vitest/polyfills/perf_hooks.js b/scripts/vite/polyfills/perf_hooks.js similarity index 100% rename from scripts/vitest/polyfills/perf_hooks.js rename to scripts/vite/polyfills/perf_hooks.js diff --git a/scripts/vitest/setupFiles/customMatchers.ts b/scripts/vitest/setupFiles/customMatchers.ts index 227c0a2c0c76..25ffeb624226 100644 --- a/scripts/vitest/setupFiles/customMatchers.ts +++ b/scripts/vitest/setupFiles/customMatchers.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import {expect} from "vitest"; expect.extend({ diff --git a/scripts/vitest/vitest.diff.ts b/scripts/vitest/vitest.diff.ts new file mode 100644 index 000000000000..9ad445b97efe --- /dev/null +++ b/scripts/vitest/vitest.diff.ts @@ -0,0 +1,9 @@ +import type {DiffOptions} from "vitest"; + +export default { + aIndicator: "--", + bIndicator: "++", + includeChangeCounts: true, + contextLines: 2, + expand: false, +} satisfies DiffOptions; diff --git a/vite.base.config.ts b/vite.base.config.ts new file mode 100644 index 000000000000..65e1bad01500 --- /dev/null +++ b/vite.base.config.ts @@ -0,0 +1,78 @@ +import {UserConfig, defineConfig} from "vite"; +import {nodePolyfills} from "vite-plugin-node-polyfills"; +import {visualizer} from "rollup-plugin-visualizer"; +import topLevelAwait from "vite-plugin-top-level-await"; +import {blsBrowserPlugin} from "./scripts/vite/plugins/blsBrowserPlugin.js"; + +export function getBaseViteConfig( + pkgInfo: { + description: string; + version: string; + author: string; + license: string; + homepage: string; + }, + {entry, libName}: {entry: string; libName: string} +): UserConfig { + // TODO: Investigate why this banner is not appended to the build header. + const banner = + `/* ${pkgInfo.description}\n` + + " * \n" + + ` * Version: ${pkgInfo.version}\n` + + ` * Author: ${pkgInfo.author}\n` + + ` * License: ${pkgInfo.license}\n` + + ` * Web: ${pkgInfo.homepage}\n` + + "*/"; + + return defineConfig({ + plugins: [ + topLevelAwait(), + blsBrowserPlugin(), + nodePolyfills({ + include: ["http", "https", "stream"], + globals: {Buffer: true, process: true}, + protocolImports: true, + }), + ...(process.env.DEBUG_BUNDLE ? [visualizer()] : []), + ], + mode: "production", + appType: "custom", + esbuild: { + banner, + legalComments: "none", + }, + build: { + // "modules" refer to ['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14'] + target: "modules", + outDir: "dist", + sourcemap: true, + minify: true, + manifest: "manifest.json", + ssr: false, + ssrManifest: false, + emptyOutDir: true, + lib: { + entry, + formats: ["es"], + name: libName, + fileName: (format) => { + if (format === "esm" || format === "es") { + return `${libName.toLowerCase()}.min.mjs`; + } else if (format === "cjs") { + return `${libName.toLowerCase()}.min.cjs`; + } else { + return `${libName.toLowerCase()}.min.${format}.js`; + } + }, + }, + rollupOptions: { + output: { + inlineDynamicImports: true, + }, + treeshake: { + preset: "recommended", + }, + }, + }, + }); +} diff --git a/vitest.base.browser.config.ts b/vitest.base.browser.config.ts index a07f4d842b06..edd53c406ae1 100644 --- a/vitest.base.browser.config.ts +++ b/vitest.base.browser.config.ts @@ -3,10 +3,12 @@ import {defineConfig} from "vitest/config"; const __dirname = new URL(".", import.meta.url).pathname; import {nodePolyfills} from "vite-plugin-node-polyfills"; import topLevelAwait from "vite-plugin-top-level-await"; +import { blsBrowserPlugin } from "./scripts/vite/plugins/blsBrowserPlugin"; export default defineConfig({ plugins: [ topLevelAwait(), + blsBrowserPlugin(), nodePolyfills({ include: ["buffer", "process", "util", "string_decoder", "url", "querystring", "events"], globals: {Buffer: true, process: true}, diff --git a/vitest.base.unit.config.ts b/vitest.base.unit.config.ts index 4e9d4c39f84e..cc123e81dffd 100644 --- a/vitest.base.unit.config.ts +++ b/vitest.base.unit.config.ts @@ -7,6 +7,8 @@ export default defineConfig({ pool: "threads", include: ["**/*.test.ts"], exclude: [ + "**/spec-tests/**", + "**/spec-tests-bls/**", "**/*.browser.test.ts", "**/node_modules/**", "**/dist/**", @@ -39,7 +41,10 @@ export default defineConfig({ "**/types/**", "**/bin/**", "**/node_modules/**", + "**/spec-tests/**", + "**/spec-tests-bls/**", ], }, + diff: process.env.TEST_COMPACT_DIFF ? path.join(import.meta.dirname, "./scripts/vitest/vitest.diff.ts") : undefined, }, }); diff --git a/yarn.lock b/yarn.lock index 05d2ec6f5e67..19f39c58ea4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -240,6 +240,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== +"@babel/parser@^7.24.1": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== + "@babel/types@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" @@ -301,10 +306,10 @@ "@chainsafe/bls-keygen" "^0.4.0" bls-eth-wasm "^0.4.8" -"@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@^0.2.11": + version "0.2.11" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.2.11.tgz#5ec85cd663592819d1dc51127e75dfd834250e3d" + integrity sha512-URyOLq5GtxBoxibOnd2pgLydCy0UZzbiIIBcsRAvGxAsRzjZL04TsQfwRkz5aphU3a1ebeRoMmI/HHyMCiFSQg== dependencies: "@types/tar" "^6.1.4" node-fetch "^2.6.1" @@ -371,10 +376,10 @@ resolved "https://registry.yarnpkg.com/@chainsafe/is-ip/-/is-ip-2.0.2.tgz#7311e7403f11d8c5cfa48111f56fcecaac37c9f6" integrity sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA== -"@chainsafe/libp2p-gossipsub@^11.2.1": - version "11.2.1" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-11.2.1.tgz#80a993cca657084c861b78513ee0ff516bfb96f9" - integrity sha512-2NvlOY4Jfwn7U/sKF0kILl3+luHxq9hhEiBqZRqLTIV8LYmMQl9VpTMgMvRwKzgn/NDeZzsPb8olk2o00tkmZw== +"@chainsafe/libp2p-gossipsub@^13.0.0": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-13.0.0.tgz#b1dfa5c2d455d77ab8dfc97f5eb8961861bb623e" + integrity sha512-2q+v429uZjMl6N3d+j9QCMj8YO0aiYvLSN1t0aTdpMXQHCHLJaaT9PtNn845B1Li7/uZjYESmikgVt8r7keH0w== dependencies: "@libp2p/crypto" "^4.0.1" "@libp2p/interface" "^1.1.2" @@ -387,7 +392,7 @@ it-pipe "^3.0.1" it-pushable "^3.2.3" multiformats "^13.0.1" - protobufjs "^7.2.6" + protons-runtime "5.4.0" uint8arraylist "^2.4.8" uint8arrays "^5.0.1" @@ -408,20 +413,19 @@ uint8arrays "^5.0.0" wherearewe "^2.0.1" -"@chainsafe/libp2p-noise@^14.1.0": - version "14.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-14.1.0.tgz#4084a448cec73a941fddfc94751f6ce2e23c07cd" - integrity sha512-uHmptoxgMsfDIP7cQMQ4Zp9+y27oON5+gloBLXi+7EJpMhyvo7tjafUxRILwLofzeAtfaF3ZHraoXRFUSbhK2Q== +"@chainsafe/libp2p-noise@^15.0.0": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-15.0.0.tgz#c3f38a31d03d96b475f7e35b592a22f5fe9269a0" + integrity sha512-O8Y/WVU4J/qrnG72jwVhbmdXiBzv1dT9B3PMClCRmZ9z/5vVPEGRVXE/SVYeGF3bNuBTLoh+F+GaKG/9UHlMhg== dependencies: "@chainsafe/as-chacha20poly1305" "^0.1.0" "@chainsafe/as-sha256" "^0.4.1" - "@libp2p/crypto" "^3.0.0" + "@libp2p/crypto" "^4.0.0" "@libp2p/interface" "^1.0.0" "@libp2p/peer-id" "^4.0.0" "@noble/ciphers" "^0.4.0" "@noble/curves" "^1.1.0" "@noble/hashes" "^1.3.1" - it-byte-stream "^1.0.0" it-length-prefixed "^9.0.1" it-length-prefixed-stream "^1.0.0" it-pair "^2.0.6" @@ -1329,7 +1333,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -1344,7 +1348,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -1362,14 +1366,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - "@jridgewell/trace-mapping@^0.3.23": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -1471,316 +1467,309 @@ yargs "16.2.0" yargs-parser "20.2.4" -"@libp2p/bootstrap@^10.0.10": - version "10.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-10.0.10.tgz#7cb64b19ecb4d6222499f50f5b3ff59f898bd316" - integrity sha512-VJ0+uNld94oGnLPyPdCLNhnOdTmqFP4E9OCAiyFZjSeaqS6qMblNR4yHz+Zgmk/sp+vNXILVYs5BRf6cW4bm/Q== +"@libp2p/bootstrap@^10.0.21": + version "10.0.21" + resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-10.0.21.tgz#be8b528604dc9634002f54d978ce6d5648d6a3ff" + integrity sha512-a9OGwyRM1ucq7ECUaxB4HdNoxCj21vXHcKce9khf44V5rUngF8Qzy07DI6/OaPyxJlXlDS19IJ7igaiYKx0TJw== dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-id" "^4.0.4" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.1.10" - -"@libp2p/crypto@^3.0.0", "@libp2p/crypto@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-3.0.4.tgz#8768b262c24a036774c6c5e290a1f0d76535a7d3" - integrity sha512-FzSwBo+RJOUzdzEwug5ZL4dAGKwEBWTLzj+EmUTHHY6c87+oLh571DQk/w0oYObSD9hYbcKePgSBaZeBx0JaZg== - dependencies: - "@libp2p/interface" "^1.1.1" - "@noble/curves" "^1.1.0" - "@noble/hashes" "^1.3.1" - multiformats "^13.0.0" - node-forge "^1.1.0" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" + "@multiformats/multiaddr" "^12.2.1" -"@libp2p/crypto@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-4.0.1.tgz#350f3397c8fba18d30a74173c3791fe199821062" - integrity sha512-lKGbX8TvQt4JbqlttdexEz2VtYJnTwY31kVBDQviwt0pMF+6Uy2hzNnEQ1FHZBwnow8BIlyb6UevHfgyOFlnkw== +"@libp2p/crypto@^4.0.0", "@libp2p/crypto@^4.0.1", "@libp2p/crypto@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-4.1.0.tgz#722060a77ced262dc89c7e42fc19ae67506b74ac" + integrity sha512-Gu4jkSdrVk1LOeyiOAuktmtN5pbSq6b9byzch2CfclFGZgXrHg3b46I0Fy63nZBc60Wq2KID3MQMVuRkVkDwAw== dependencies: - "@libp2p/interface" "^1.1.2" - "@noble/curves" "^1.1.0" - "@noble/hashes" "^1.3.3" + "@libp2p/interface" "^1.3.0" + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" asn1js "^3.0.5" - multiformats "^13.0.0" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.7" - uint8arrays "^5.0.0" - -"@libp2p/identify@^1.0.9": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@libp2p/identify/-/identify-1.0.9.tgz#6756d74919b7a171c7cdcdce45669b9f633fbb0f" - integrity sha512-zDJofRDMlB3XYM2vvH/D/XrFeE9JzwVW09GPTMplGoECdq25Id7V4nWhkdNOmAQOQkhl/lFZmZHF7ZjCDgLybQ== - dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/interface-internal" "^1.0.5" - "@libp2p/peer-id" "^4.0.4" - "@libp2p/peer-record" "^7.0.4" - "@multiformats/multiaddr" "^12.1.10" - "@multiformats/multiaddr-matcher" "^1.1.0" - it-protobuf-stream "^1.0.2" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" + multiformats "^13.1.0" + protons-runtime "^5.4.0" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" + +"@libp2p/identify@^1.0.20": + version "1.0.20" + resolved "https://registry.yarnpkg.com/@libp2p/identify/-/identify-1.0.20.tgz#cce6c4efad77afe6c0b26b0704a902f2fdbaeab2" + integrity sha512-bhn57ZI4MIMn0p3S6YNc8Sr5ReA8We8bVU25lNAefVUO3gMeQOMZ6FdTVJKbxoSumvZ+q8ciB2IOvu4rMU7o1g== + dependencies: + "@libp2p/interface" "^1.3.0" + "@libp2p/interface-internal" "^1.1.1" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/peer-record" "^7.0.15" + "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr-matcher" "^1.2.0" + it-protobuf-stream "^1.1.2" + protons-runtime "^5.4.0" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" wherearewe "^2.0.1" -"@libp2p/interface-internal@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.0.5.tgz#b7687e4c5cb765fd686fcd442d2cc4c49e8304d7" - integrity sha512-qT4APD2nZKEGnkn4LfM2mzNbYv9bx/2FyvYaJ4exjzIIBPiRmjrek7hfWErKkazCDwO51+WuZ/DERdd32O9Fxg== - dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-collections" "^5.1.3" - "@multiformats/multiaddr" "^12.1.10" - uint8arraylist "^2.4.3" - -"@libp2p/interface-internal@^1.0.7": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.0.7.tgz#e15ad52e148e31558972dd2f4800ad8be61ced88" - integrity sha512-r1nGpnGdkq0U7ow5i093OPWPBJXQP3BGwijino8cCZokYwF2P/CU+yeYvL8ncL8fPYLKuuUjLNGO4Z8Th5sqSQ== - dependencies: - "@libp2p/interface" "^1.1.2" - "@libp2p/peer-collections" "^5.1.5" - "@multiformats/multiaddr" "^12.1.10" - uint8arraylist "^2.4.7" - -"@libp2p/interface@^1.0.0", "@libp2p/interface@^1.1.1": +"@libp2p/interface-internal@^1.0.7", "@libp2p/interface-internal@^1.1.1": version "1.1.1" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.1.1.tgz#f37ea4930bd74e1299fbcafa49fdab39a28abba9" - integrity sha512-g6xgF+q38ZDTRkjuJfuOByS4N0zGld+VPRiWPXYX8wA/9vS6lqJwKUoC6V33KUhP/zXHCkJaSD6z94fUbNM8vw== + resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.1.1.tgz#ff16b4fee4a3d3e39121e26eeeab42e9257f5f49" + integrity sha512-lLPd7yysXqpb1oiPZAn57w3CQdD33C+mu6pfUuPYI5yWMgwWq8V3XE4IMG1IyHUGEYZAuGglghAH9YQNbtticw== dependencies: - "@multiformats/multiaddr" "^12.1.10" - it-pushable "^3.2.1" - it-stream-types "^2.0.1" - multiformats "^13.0.0" - progress-events "^1.0.0" - uint8arraylist "^2.4.3" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-collections" "^5.1.11" + "@multiformats/multiaddr" "^12.2.1" + uint8arraylist "^2.4.8" -"@libp2p/interface@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.1.2.tgz#debfd9d1bd4b81929c9e30eb35c2801ca246ce2b" - integrity sha512-uC4hxtEJuWiDiZfokkSNEEbCzdyZrqb5kp67Wc5PjZsySZ2IoImdIfie003yQXlB1xBp/XUJzdC6kVu4M7LUmg== +"@libp2p/interface@^1.0.0", "@libp2p/interface@^1.1.1", "@libp2p/interface@^1.1.2", "@libp2p/interface@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.3.0.tgz#c4fcee2878aa8d37357974b6c7395cb2a645eb50" + integrity sha512-K72Km0Co1Z+pXpggWuoAvUUbvwZYvjCcywrHj2Ym3jt2anTE3hzL4rlZrrkzA0YhNTRFRiZ04dnu6WMXT5/4+A== dependencies: - "@multiformats/multiaddr" "^12.1.10" + "@multiformats/multiaddr" "^12.2.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" - multiformats "^13.0.0" + multiformats "^13.1.0" progress-events "^1.0.0" - uint8arraylist "^2.4.7" - -"@libp2p/logger@^4.0.1", "@libp2p/logger@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.4.tgz#98c5357e8b857d93a506f6818db6abe734d342ee" - integrity sha512-lr6/Cmj9VhtET4ZnRhWls4kY4K5moTAIEZtZugmkflT4qJXJywkmn/EpLO3kjgE+PDjrgOr8lUVVJBGvEHL8Jg== - dependencies: - "@libp2p/interface" "^1.1.1" - "@multiformats/multiaddr" "^12.1.10" - debug "^4.3.4" - interface-datastore "^8.2.0" - multiformats "^13.0.0" + uint8arraylist "^2.4.8" -"@libp2p/logger@^4.0.5": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.5.tgz#6790776b4b2d587b75ccbdf85885c5d11533d19f" - integrity sha512-cXETMNZINnxeQBlfQ2S4di92FDDU89R7RHagrpebGrM7oLl5nf/Mw6myc23kGaM3/2YG3ko2rl9sYjemu0azTA== +"@libp2p/logger@^4.0.11", "@libp2p/logger@^4.0.6": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.11.tgz#671692a0cceee73a0c0bf9b5f05ea14fde05f5e5" + integrity sha512-WsZBup1Q+ec4C7i2YiCx0elFrejqJea3Fmkzy3t4fAek7Ofyh4GQonk3A4R7XsG5yq8+Hu1fpsGhIK8EVQsqZQ== dependencies: - "@libp2p/interface" "^1.1.2" - "@multiformats/multiaddr" "^12.1.10" + "@libp2p/interface" "^1.3.0" + "@multiformats/multiaddr" "^12.2.1" debug "^4.3.4" - interface-datastore "^8.2.0" - multiformats "^13.0.0" - -"@libp2p/mdns@^10.0.10": - version "10.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-10.0.10.tgz#02f08f1a485e3640ce575460af63a0b8c4171b64" - integrity sha512-Zxwbvg+rkmjE5YNue9Bldl/mpQS3BPMZlPPLjwQkVFRVjJdsBuWAWNFy08rzjYZunjBP1N4RMUdncrbjAYnoSg== - dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/interface-internal" "^1.0.5" - "@libp2p/peer-id" "^4.0.4" - "@libp2p/utils" "^5.2.0" - "@multiformats/multiaddr" "^12.1.10" - "@types/multicast-dns" "^7.2.1" - dns-packet "^5.4.0" + interface-datastore "^8.2.11" + multiformats "^13.1.0" + +"@libp2p/mdns@^10.0.21": + version "10.0.21" + resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-10.0.21.tgz#028a388b73de703e4c762fd4937f217648c8128c" + integrity sha512-/lmjsZJvhfEXeSodqKECiRZk8mqApESc3OI6MhHxNvRBsfncY93IZM7lR6jwlmyQ2DOL5rCkm2rcr9geIsVzmQ== + dependencies: + "@libp2p/interface" "^1.3.0" + "@libp2p/interface-internal" "^1.1.1" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/utils" "^5.3.2" + "@multiformats/multiaddr" "^12.2.1" + "@types/multicast-dns" "^7.2.4" + dns-packet "^5.6.1" multicast-dns "^7.2.5" -"@libp2p/mplex@^10.0.10": - version "10.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-10.0.10.tgz#04476551f8ab205c2b6754cc94692264a883629b" - integrity sha512-vwyqjuc/P/co5Kj+FknYl2BJ69es+rM8TmtQ5e/xnTDpaD2JPGIeMhKXC3hSNAIvmL9OHdwqzLGHD98vRfMv/A== +"@libp2p/mplex@^10.0.21": + version "10.0.21" + resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-10.0.21.tgz#530de45f23dd36d5ac35e21a1c259767c5bfdab1" + integrity sha512-F7pK/xG9LNG3KhZBMb6SsiR7MI18na1x1e1qr8EvlyJcmdT0OiiHCnjDXWrmy+wh6uTD2qhRM+ea1vQEhKANXw== dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/utils" "^5.2.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/utils" "^5.3.2" it-pipe "^3.0.1" - it-pushable "^3.2.1" + it-pushable "^3.2.3" it-stream-types "^2.0.1" - rate-limiter-flexible "^4.0.0" - uint8-varint "^2.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" + uint8-varint "^2.0.4" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" -"@libp2p/multistream-select@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-5.1.1.tgz#81b7eddf33a3b87cfbf70bb69c9ae548afb43800" - integrity sha512-hdcsmrqF0ffh/dNjw+KKfllXIJocpxWzlNSGWxswsmoZFV0Krx7HH/kHQDr5f2mehrO08wJyzRCnlKv9LrirAQ== +"@libp2p/multistream-select@^5.1.8": + version "5.1.8" + resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-5.1.8.tgz#c484534496625da2a20873874b33e90d3ef2a95e" + integrity sha512-mYbYyjKhNOGIaS3kefs+koofGmiBvLukcnS+BVCZDGjYxAjhaes9PB++VyuX/D0lTZSk08P3cIBvw2sN+amOVQ== dependencies: - "@libp2p/interface" "^1.1.1" - it-length-prefixed "^9.0.3" - it-length-prefixed-stream "^1.1.1" + "@libp2p/interface" "^1.3.0" + it-length-prefixed "^9.0.4" + it-length-prefixed-stream "^1.1.6" it-stream-types "^2.0.1" - p-defer "^4.0.0" + p-defer "^4.0.1" race-signal "^1.0.2" - uint8-varint "^2.0.2" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" - -"@libp2p/peer-collections@^5.1.3", "@libp2p/peer-collections@^5.1.5": - version "5.1.5" - resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-5.1.5.tgz#8b241f129dd94f5b56a17fc0614b8e9b80687b44" - integrity sha512-/9VisdPC7+15n/0XntjGCzJ2Ky/zZnqdnuLNEwdu2LuTCbWTaqItG36ecgcVdO9L/V4mELwgY5XCjZKBDrYgjA== - dependencies: - "@libp2p/interface" "^1.1.2" - "@libp2p/peer-id" "^4.0.5" - -"@libp2p/peer-id-factory@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id-factory/-/peer-id-factory-4.0.3.tgz#0d6c141ec0a0ee06a14e7c77cec22294069e30db" - integrity sha512-IdSMwn6ogrHOUR6xPhgu6ZMZrIhvnRRJBnslCr09ATzir1Vs77s06OpXiMrZQ5xbEbLJuD52PE8s1Oz2Ei/iLg== - dependencies: - "@libp2p/crypto" "^3.0.4" - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-id" "^4.0.4" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" - -"@libp2p/peer-id@^4.0.0", "@libp2p/peer-id@^4.0.4", "@libp2p/peer-id@^4.0.5": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-4.0.5.tgz#ed8be246b4d7ba2b7806968b4bfa8d59b82a4b2a" - integrity sha512-/J9U6I/CWSOsYrTpFZpRQrhOhi+bp9WFp7+9Gc7kVt/oevIYTapUEjpxevjViem9ddR5RbdYeCj4ZLHA04QOoQ== - dependencies: - "@libp2p/interface" "^1.1.2" - multiformats "^13.0.0" - uint8arrays "^5.0.0" + uint8-varint "^2.0.4" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" -"@libp2p/peer-record@^7.0.4": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-7.0.4.tgz#8c19cef2a3d82da576942440d67c482c5a0f344a" - integrity sha512-4UXsfo22qT3BnWfBkGp0jgrNPJjBI60ehZV9piB/3EIeT7hLIvuBuBbn3+QM87ew5D5vpvwr+Lo1CyampqbB7g== +"@libp2p/peer-collections@^5.1.11": + version "5.1.11" + resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-5.1.11.tgz#55589fccb4daf6a9f611f3e4126d2721d856aaca" + integrity sha512-w8ZeXfsAxBQiYgRnvpD3mxGORxwAXFsIhAOxFXl8scFhuE1j086PoTfRTuKYfp4DAyNHWkhUd+LQaXN0OG/Fgg== dependencies: - "@libp2p/crypto" "^3.0.4" - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-id" "^4.0.4" - "@libp2p/utils" "^5.2.0" - "@multiformats/multiaddr" "^12.1.10" - protons-runtime "^5.0.0" - uint8-varint "^2.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" -"@libp2p/peer-record@^7.0.7": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-7.0.7.tgz#e55145b2509592696f42ff73c38f813efbbbc688" - integrity sha512-RsggFJVAWQBA2z+ZJsK5nKHDKLmSd89IhFiE5GyImedQFiMkJz/gDFROzfNF2NdOyEBNdRy5SmC9scNFRQQD9A== +"@libp2p/peer-id-factory@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@libp2p/peer-id-factory/-/peer-id-factory-4.1.0.tgz#e134ff61c38d1a0fd210bf1fbdcd9116a74f2919" + integrity sha512-EMovpqtqj+5s+QpzSkVundoPQ88/GQMShB79Y6zLUkGZ73VtqWds/9e1WsrHBx6HhvmkmXFOrzcW8qfml3sE7A== dependencies: - "@libp2p/crypto" "^4.0.1" - "@libp2p/interface" "^1.1.2" - "@libp2p/peer-id" "^4.0.5" - "@libp2p/utils" "^5.2.3" - "@multiformats/multiaddr" "^12.1.10" - protons-runtime "^5.0.0" - uint8-varint "^2.0.2" - uint8arraylist "^2.4.7" - uint8arrays "^5.0.0" + "@libp2p/crypto" "^4.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" + protons-runtime "^5.4.0" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" -"@libp2p/peer-store@^10.0.5": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-10.0.5.tgz#b969d1707f5dcbf4d110e099270de285b075aa02" - integrity sha512-n+rwX8HNkyquOeL6vkcGJMesJsauKBuBIeMG+OnBY3mfFjaVjtGeHF2DQniS6AXHt2hktK9TlC2NEDRh6oGvRw== - dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-collections" "^5.1.3" - "@libp2p/peer-id" "^4.0.4" - "@libp2p/peer-record" "^7.0.4" - "@multiformats/multiaddr" "^12.1.10" - interface-datastore "^8.2.0" - it-all "^3.0.2" - mortice "^3.0.1" - multiformats "^13.0.0" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^5.0.0" +"@libp2p/peer-id@^4.0.0", "@libp2p/peer-id@^4.0.4", "@libp2p/peer-id@^4.0.5", "@libp2p/peer-id@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-4.1.0.tgz#460e07d5b25339cf80afcb5e30c4f701423d1755" + integrity sha512-XmuqEfz3H+Cwq72V3opXg7wK2WnB08VEnG5nLILefLg+qo1KMlUP5pCP3ffyvYIvxMnsRla/xPYRDEBtL2JMpg== + dependencies: + "@libp2p/interface" "^1.3.0" + multiformats "^13.1.0" + uint8arrays "^5.0.3" + +"@libp2p/peer-record@^7.0.15", "@libp2p/peer-record@^7.0.7": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-7.0.15.tgz#063f302fb52ebe6c548a4533e3fa3b910efdfc84" + integrity sha512-VNDjLAuDF+CHf50+50CZQeT341kJm0GuWhuOqlzonOlJihpm5314Xe1BV3oeLgrtdp1ikLvQ099JqZN/l4KIQQ== + dependencies: + "@libp2p/crypto" "^4.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/utils" "^5.3.2" + "@multiformats/multiaddr" "^12.2.1" + protons-runtime "^5.4.0" + uint8-varint "^2.0.4" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" + +"@libp2p/peer-store@^10.0.16": + version "10.0.16" + resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-10.0.16.tgz#0bde6e2185e416a137d8adb7b2c381bfe4acf535" + integrity sha512-xzitLNXnCG8eAs3KT5j0sBkK0ooChv4QDqjEzCNr+Gzwryi2fn386KlPoCGNkbeAUsIHS81TY/ldK8o8NBac7Q== + dependencies: + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-collections" "^5.1.11" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/peer-record" "^7.0.15" + "@multiformats/multiaddr" "^12.2.1" + interface-datastore "^8.2.11" + it-all "^3.0.4" + mortice "^3.0.4" + multiformats "^13.1.0" + protons-runtime "^5.4.0" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" -"@libp2p/prometheus-metrics@^3.0.10": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-3.0.10.tgz#b95f4c6f20817fb157b803012034baccc588ddb5" - integrity sha512-ESOWM2uAM8X2fjb1nZF98LkYs/Nf2Ifxnfj3LVdSlaYbz44jDvCQ2ZW5vpGfooonVnU2Jkm5kvEeCWYt/9y8mQ== +"@libp2p/prometheus-metrics@^3.0.21": + version "3.0.21" + resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-3.0.21.tgz#78b3327a614aacc62886597d6c6eb67c5597b8db" + integrity sha512-sqU8pI9CG/b86YUEt3IaE3ZSbauBfKbxFRdSiYVRN8EbliGxQC9blgwUcGDfWW2qcXZEgM4m2FTDLZrujFDbzA== dependencies: - "@libp2p/interface" "^1.1.1" - it-foreach "^2.0.3" + "@libp2p/interface" "^1.3.0" + it-foreach "^2.0.6" it-stream-types "^2.0.1" - prom-client "^15.0.0" - uint8arraylist "^2.4.3" + prom-client "^15.1.1" + uint8arraylist "^2.4.8" "@libp2p/pubsub@^9.0.8": - version "9.0.8" - resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-9.0.8.tgz#4c222c94edb5a5b623ed10fa7555bb70a19ddc0d" - integrity sha512-p2UEfjQPMQgEJTXPdinWCMA6A1sLR7Hvfu8mtoOS1azgtTtqmMCNPtx+3acnNSnWItQFswl9w2HWjspfUcCF1w== - dependencies: - "@libp2p/crypto" "^4.0.1" - "@libp2p/interface" "^1.1.2" - "@libp2p/interface-internal" "^1.0.7" - "@libp2p/peer-collections" "^5.1.5" - "@libp2p/peer-id" "^4.0.5" - "@libp2p/utils" "^5.2.3" - it-length-prefixed "^9.0.3" + version "9.0.16" + resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-9.0.16.tgz#90857f494213f7a596df15081956514728e14aa2" + integrity sha512-SCV0eZuYMyhHhBFzUBslHjvfwKfL2UMZSSr08c7MsTrqvQQSVdiCEeGKfoR70h7BUvBBQkPLcCqTFZGRoYX8dA== + dependencies: + "@libp2p/crypto" "^4.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/interface-internal" "^1.1.1" + "@libp2p/peer-collections" "^5.1.11" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/utils" "^5.3.2" + it-length-prefixed "^9.0.4" it-pipe "^3.0.1" it-pushable "^3.2.3" - multiformats "^13.0.0" - p-queue "^8.0.0" - uint8arraylist "^2.4.7" - uint8arrays "^5.0.0" + multiformats "^13.1.0" + p-queue "^8.0.1" + uint8arraylist "^2.4.8" + uint8arrays "^5.0.3" -"@libp2p/tcp@9.0.10": - version "9.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-9.0.10.tgz#94ad87f728b857651608582393f33a8ca095c69d" - integrity sha512-ixwa2aDpCiS3ng/TjLB/7QIWChmlKEmH6L/vS089chJ7M5mYqRJdbLeo4zfod6lSmJab2mj8Q0sKzGeplAPE5Q== +"@libp2p/tcp@9.0.23": + version "9.0.23" + resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-9.0.23.tgz#44eed016fdbe4725726d451a67af548507f5591b" + integrity sha512-ERX7b//PEmy4AwhjkjLx83ZpfwTlrbDt12TEn4+ZDqtsx1lzgCjuNVUy3joSWMu9ySIvMjnzxm7mxlkAJd8buw== dependencies: - "@libp2p/interface" "^1.1.1" - "@libp2p/utils" "^5.2.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/utils" "^5.3.2" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.1.10" - "@types/sinon" "^17.0.0" - stream-to-it "^0.2.2" + "@multiformats/multiaddr" "^12.2.1" + "@types/sinon" "^17.0.3" + stream-to-it "^1.0.0" -"@libp2p/utils@^5.2.0", "@libp2p/utils@^5.2.3": - version "5.2.3" - resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-5.2.3.tgz#32c1dd68d661d7d93ed3428c7817da2e4b85817f" - integrity sha512-N+9pQHQ/XrxXP/RCiWUSUXnkFCWcyzMxlGXY+aQUfcfLi5M2eFtPSz2Tc5dWmYGVJeI9CNafok+72YUsPZHfOQ== +"@libp2p/utils@^5.3.2": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-5.3.2.tgz#044881910350fb22ed0f9db35e6f68f7e8948801" + integrity sha512-3HVixx17xT7JCEY931Gd2E2WmtY0RQirDeb6OZ1YD0T3VdWUMxH7pdf1gZpCHjQTg18ISIItZnFCGy+NyoYv6Q== dependencies: "@chainsafe/is-ip" "^2.0.2" - "@libp2p/interface" "^1.1.2" - "@libp2p/logger" "^4.0.5" - "@multiformats/multiaddr" "^12.1.10" - "@multiformats/multiaddr-matcher" "^1.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/logger" "^4.0.11" + "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr-matcher" "^1.2.0" delay "^6.0.0" get-iterator "^2.0.1" - is-loopback-addr "^2.0.1" + is-loopback-addr "^2.0.2" it-pushable "^3.2.3" it-stream-types "^2.0.1" netmask "^2.0.2" - p-defer "^4.0.0" - race-event "^1.1.0" + p-defer "^4.0.1" + race-event "^1.2.0" race-signal "^1.0.2" - uint8arraylist "^2.4.7" + uint8arraylist "^2.4.8" "@lukeed/ms@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.1.tgz#3c2bbc258affd9cc0e0cc7828477383c73afa6ee" integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA== +"@microsoft/api-extractor-model@7.28.13": + version "7.28.13" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz#96fbc52155e0d07e0eabbd9699065b77702fe33a" + integrity sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw== + dependencies: + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "~0.16.1" + "@rushstack/node-core-library" "4.0.2" + +"@microsoft/api-extractor@7.43.0": + version "7.43.0" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz#41c42677bc71cd8e0f23c63c56802d85044e65cd" + integrity sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w== + dependencies: + "@microsoft/api-extractor-model" "7.28.13" + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "~0.16.1" + "@rushstack/node-core-library" "4.0.2" + "@rushstack/rig-package" "0.5.2" + "@rushstack/terminal" "0.10.0" + "@rushstack/ts-command-line" "4.19.1" + lodash "~4.17.15" + minimatch "~3.0.3" + resolve "~1.22.1" + semver "~7.5.4" + source-map "~0.6.1" + typescript "5.4.2" + +"@microsoft/tsdoc-config@~0.16.1": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" + integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== + dependencies: + "@microsoft/tsdoc" "0.14.2" + ajv "~6.12.6" + jju "~1.4.0" + resolve "~1.19.0" + +"@microsoft/tsdoc@0.14.2": + version "0.14.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" + integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== + +"@multiformats/dns@^1.0.3", "@multiformats/dns@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@multiformats/dns/-/dns-1.0.6.tgz#b8c7de11459a02a5f4e609d35d3cdb95cb6ad152" + integrity sha512-nt/5UqjMPtyvkG9BQYdJ4GfLK3nMqGpFZOzf4hAmIa0sJh2LlS9YKXZ4FgwBDsaHvzZqR/rUFIywIc7pkHNNuw== + dependencies: + "@types/dns-packet" "^5.6.5" + buffer "^6.0.3" + dns-packet "^5.6.1" + hashlru "^2.3.0" + p-queue "^8.0.1" + progress-events "^1.0.0" + uint8arrays "^5.0.2" + "@multiformats/mafmt@^12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@multiformats/mafmt/-/mafmt-12.1.6.tgz#e7c1831c1e94c94932621826049afc89f3ad43b7" @@ -1788,24 +1777,24 @@ dependencies: "@multiformats/multiaddr" "^12.0.0" -"@multiformats/multiaddr-matcher@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.1.0.tgz#27e14a549a00594c24d85897c4b0b7e83df3e59d" - integrity sha512-B/QbKpAxaHYVXFnbTdTgYqPDxmqoF2RYffwYoOv1MWfi2vBCZLdzmEKUBKv6fQr6s+LJFSHn2j2vczmwMFCQIA== +"@multiformats/multiaddr-matcher@^1.1.0", "@multiformats/multiaddr-matcher@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.2.0.tgz#8a2beae9eff394861668e6a2776fb1e7bf719c81" + integrity sha512-LH6yR7h3HSNKcxuvvi2UpLuowuVkYC6H9Y3jqmKuTai8XtKnXtW6NcDZFD/ooTBY+H4yX/scoJpjOalHrk5qdQ== dependencies: "@chainsafe/is-ip" "^2.0.1" "@multiformats/multiaddr" "^12.0.0" - multiformats "^12.0.1" + multiformats "^13.0.0" -"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.10", "@multiformats/multiaddr@^12.1.14", "@multiformats/multiaddr@^12.1.3": - version "12.1.14" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.1.14.tgz#d021072667f4dfc566cdddcb45feee60fecc8cfd" - integrity sha512-1C0Mo73chzu7pTzTquuKs5vUtw70jhqg1i6pUNznGb0WV6RFa6vyB+D697Os5+cLx+DiItrAY6VzMtlGQsMzYg== +"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.10", "@multiformats/multiaddr@^12.1.14", "@multiformats/multiaddr@^12.1.3", "@multiformats/multiaddr@^12.2.1": + version "12.2.1" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.2.1.tgz#d95d1590b17dbe39dcefbb4d832d14434d3fe075" + integrity sha512-UwjoArBbv64FlaetV4DDwh+PUMfzXUBltxQwdh+uTYnGFzVa8ZfJsn1vt1RJlJ6+Xtrm3RMekF/B+K338i2L5Q== dependencies: "@chainsafe/is-ip" "^2.0.1" "@chainsafe/netmask" "^2.0.0" "@libp2p/interface" "^1.0.0" - dns-over-http-resolver "^3.0.2" + "@multiformats/dns" "^1.0.3" multiformats "^13.0.0" uint8-varint "^2.0.1" uint8arrays "^5.0.0" @@ -1887,16 +1876,28 @@ dependencies: "@noble/hashes" "1.3.3" +"@noble/curves@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + "@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== -"@noble/hashes@1.3.3", "@noble/hashes@^1.0.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3", "@noble/hashes@~1.3.2": +"@noble/hashes@1.3.3", "@noble/hashes@^1.0.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@1.4.0", "@noble/hashes@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@noble/hashes@~1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.0.0.tgz#d5e38bfbdaba174805a4e649f13be9a9ed3351ae" @@ -2451,59 +2452,6 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - "@puppeteer/browsers@1.4.6", "@puppeteer/browsers@^1.6.0", "@puppeteer/browsers@^2.1.0": version "2.2.2" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.2.2.tgz#c43b00a9808370fec3e548779d81d1e0b972e8bb" @@ -2541,6 +2489,15 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/pluginutils@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" + integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + "@rollup/rollup-android-arm-eabi@4.16.1": version "4.16.1" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.1.tgz#ad76cc870b1e2bc4476dfc02b82e20cea272a09d" @@ -2621,6 +2578,44 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.1.tgz#5068a893ba292279adbe76fc487316724b15d811" integrity sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w== +"@rushstack/node-core-library@4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz#e26854a3314b279d57e8abdb4acce7797d02f554" + integrity sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg== + dependencies: + fs-extra "~7.0.1" + import-lazy "~4.0.0" + jju "~1.4.0" + resolve "~1.22.1" + semver "~7.5.4" + z-schema "~5.0.2" + +"@rushstack/rig-package@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.5.2.tgz#0e23a115904678717a74049661931c0b37dd5495" + integrity sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA== + dependencies: + resolve "~1.22.1" + strip-json-comments "~3.1.1" + +"@rushstack/terminal@0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.10.0.tgz#e81909fa0e5c8016b6df4739f0f381f44358269f" + integrity sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw== + dependencies: + "@rushstack/node-core-library" "4.0.2" + supports-color "~8.1.1" + +"@rushstack/ts-command-line@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz#288ee54dd607e558a8be07705869c16c31b5c3ef" + integrity sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg== + dependencies: + "@rushstack/terminal" "0.10.0" + "@types/argparse" "1.0.38" + argparse "~1.0.9" + string-argv "~0.3.1" + "@scure/base@~1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.0.0.tgz#109fb595021de285f05a7db6806f2f48296fcee7" @@ -2841,17 +2836,10 @@ "@tufjs/canonical-json" "1.0.0" minimatch "^9.0.0" -"@types/abstract-leveldown@*": - version "5.0.1" - resolved "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz" - integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== - -"@types/buffer-xor@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/buffer-xor/-/buffer-xor-2.0.2.tgz#d8c463583b8fbb322ea824562dc78a0c3cea2ca6" - integrity sha512-OqdCua7QCTupPnJgmyGJUpxWgbuOi0IMIVslXTSePS2o+qDrDB6f2Pg44zRyqhUA5GbFAf39U8z0+mH4WG0fLQ== - dependencies: - "@types/node" "*" +"@types/argparse@1.0.38": + version "1.0.38" + resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" + integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== "@types/cacheable-request@^6.0.1": version "6.0.3" @@ -2884,6 +2872,13 @@ dependencies: "@types/node" "*" +"@types/dns-packet@^5.6.5": + version "5.6.5" + resolved "https://registry.yarnpkg.com/@types/dns-packet/-/dns-packet-5.6.5.tgz#49fc29a40f5d30227ed028fa1ee82601d3745e15" + integrity sha512-qXOC7XLOEe43ehtWJCMnQXvgcIpv6rPmQ1jXT98Ad8A3TB1Ue50jsCbSSSyuazScEuZ/Q026vHbrOTVkmwA+7Q== + dependencies: + "@types/node" "*" + "@types/estree@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" @@ -2933,11 +2928,6 @@ "@types/through" "*" rxjs "^7.2.0" -"@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - "@types/js-yaml@^4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" @@ -2948,6 +2938,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" @@ -2960,14 +2955,6 @@ dependencies: "@types/node" "*" -"@types/leveldown@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/leveldown/-/leveldown-4.0.3.tgz#4b868fd747808d378df6ffb27de7f889cae46aad" - integrity sha512-fzIXOuUCSZQKkRadWhURwu6mMYbfqi/nRDA+yBwz8kj7AK/L7L//u6A0MqSv0gsilzo7N/5+FlZOx8G6m03EVQ== - dependencies: - "@types/abstract-leveldown" "*" - "@types/node" "*" - "@types/minimatch@^3.0.3": version "3.0.5" resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz" @@ -2988,10 +2975,10 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/multicast-dns@^7.2.1": - version "7.2.1" - resolved "https://registry.yarnpkg.com/@types/multicast-dns/-/multicast-dns-7.2.1.tgz#6527b28ce62bcdc08a38f6a329a3d23145c99d95" - integrity sha512-A2PmB8MRcNVEkw6wzGT5rtBHqyHOVjiRMkJH+zpJKXipSi+GGkHg6JjNFApDiYK9WefJqkVG0taln1VMl4TGfw== +"@types/multicast-dns@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@types/multicast-dns/-/multicast-dns-7.2.4.tgz#50bc357f832c884ad8540e372169108855bceb05" + integrity sha512-ib5K4cIDR4Ro5SR3Sx/LROkMDa0BHz0OPaCBL/OSPDsAXEGZ3/KQeS6poBKYVN7BfjXDL9lWNwzyHVgt/wkyCw== dependencies: "@types/dns-packet" "*" "@types/node" "*" @@ -3004,7 +2991,7 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@>=13.7.0": +"@types/node@*": version "20.6.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.5.tgz#4c6a79adf59a8e8193ac87a0e522605b16587258" integrity sha512-2qGq5LAOTh9izcc0+F+dToFigBWiK1phKPt7rNhOqJSr35y8rlIBjDwGtFSgAI6MGIhjwOVNSQZVdJsZJ2uR1w== @@ -3026,10 +3013,10 @@ dependencies: undici-types "~5.26.4" -"@types/node@^20.11.28": - version "20.11.28" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.28.tgz#4fd5b2daff2e580c12316e457473d68f15ee6f66" - integrity sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA== +"@types/node@^20.12.8": + version "20.12.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.8.tgz#35897bf2bfe3469847ab04634636de09552e8256" + integrity sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w== dependencies: undici-types "~5.26.4" @@ -3075,10 +3062,15 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== -"@types/sinon@^17.0.0": - version "17.0.2" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.2.tgz#9a769f67e62b45b7233f1fe01cb1f231d2393e1c" - integrity sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA== +"@types/semver@^7.5.8": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + +"@types/sinon@^17.0.3": + version "17.0.3" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.3.tgz#9aa7e62f0a323b9ead177ed23a36ea757141a5fa" + integrity sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw== dependencies: "@types/sinonjs__fake-timers" "*" @@ -3216,6 +3208,14 @@ "@typescript-eslint/types" "7.2.0" "@typescript-eslint/visitor-keys" "7.2.0" +"@typescript-eslint/scope-manager@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz#3f0db079b275bb8b0cb5be7613fb3130cfb5de77" + integrity sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw== + dependencies: + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" + "@typescript-eslint/type-utils@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz#7be5c30e9b4d49971b79095a1181324ef6089a19" @@ -3231,6 +3231,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f" integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA== +"@typescript-eslint/types@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.7.0.tgz#23af4d24bf9ce15d8d301236e3e3014143604f27" + integrity sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w== + "@typescript-eslint/typescript-estree@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556" @@ -3245,7 +3250,21 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@7.2.0", "@typescript-eslint/utils@^7.1.1": +"@typescript-eslint/typescript-estree@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz#b5dd6383b4c6a852d7b256a37af971e8982be97f" + integrity sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ== + dependencies: + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.2.0.tgz#fc8164be2f2a7068debb4556881acddbf0b7ce2a" integrity sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA== @@ -3258,6 +3277,19 @@ "@typescript-eslint/typescript-estree" "7.2.0" semver "^7.5.4" +"@typescript-eslint/utils@^7.1.1": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.7.0.tgz#3d2b6606a60ac34f3c625facfb3b3ab7e126f58d" + integrity sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.15" + "@types/semver" "^7.5.8" + "@typescript-eslint/scope-manager" "7.7.0" + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/typescript-estree" "7.7.0" + semver "^7.6.0" + "@typescript-eslint/visitor-keys@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e" @@ -3266,24 +3298,32 @@ "@typescript-eslint/types" "7.2.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz#950148cf1ac11562a2d903fdf7acf76714a2dc9e" + integrity sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA== + dependencies: + "@typescript-eslint/types" "7.7.0" + eslint-visitor-keys "^3.4.3" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@vitest/browser@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/browser/-/browser-1.4.0.tgz#c210b235eecc602615f6970d6036d37b79fb1dc9" - integrity sha512-kC44DzuqPZZrqe2P7SX2a3zHDAt919WtpkUMAxzv9eP5uPfVXtpk2Ipms2NXJGY5190aJc1uY+ambfJ3rwDJRA== +"@vitest/browser@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/browser/-/browser-1.6.0.tgz#08ec3003e24b093d376f79992a036b64ec780bf3" + integrity sha512-3Wpp9h1hf++rRVPvoXevkdHybLhJVn7MwIMKMIh08tVaoDMmT6fnNhbP222Z48V9PptpYeA5zvH9Ct/ZcaAzmQ== dependencies: - "@vitest/utils" "1.4.0" + "@vitest/utils" "1.6.0" magic-string "^0.30.5" sirv "^2.0.4" -"@vitest/coverage-v8@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.4.0.tgz#78ba9e182ff4cd1eba79c45cfafd2edc4c2941ec" - integrity sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg== +"@vitest/coverage-v8@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz#2f54ccf4c2d9f23a71294aba7f95b3d2e27d14e7" + integrity sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew== dependencies: "@ampproject/remapping" "^2.2.1" "@bcoe/v8-coverage" "^0.2.3" @@ -3298,7 +3338,6 @@ std-env "^3.5.0" strip-literal "^2.0.0" test-exclude "^6.0.0" - v8-to-istanbul "^9.2.0" "@vitest/expect@1.2.1": version "1.2.1" @@ -3309,13 +3348,13 @@ "@vitest/utils" "1.2.1" chai "^4.3.10" -"@vitest/expect@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.4.0.tgz#d64e17838a20007fecd252397f9b96a1ca81bfb0" - integrity sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA== +"@vitest/expect@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30" + integrity sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ== dependencies: - "@vitest/spy" "1.4.0" - "@vitest/utils" "1.4.0" + "@vitest/spy" "1.6.0" + "@vitest/utils" "1.6.0" chai "^4.3.10" "@vitest/runner@1.2.1": @@ -3327,12 +3366,12 @@ p-limit "^5.0.0" pathe "^1.1.1" -"@vitest/runner@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.4.0.tgz#907c2d17ad5975b70882c25ab7a13b73e5a28da9" - integrity sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg== +"@vitest/runner@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.0.tgz#a6de49a96cb33b0e3ba0d9064a3e8d6ce2f08825" + integrity sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg== dependencies: - "@vitest/utils" "1.4.0" + "@vitest/utils" "1.6.0" p-limit "^5.0.0" pathe "^1.1.1" @@ -3345,10 +3384,10 @@ pathe "^1.1.1" pretty-format "^29.7.0" -"@vitest/snapshot@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.4.0.tgz#2945b3fb53767a3f4f421919e93edfef2935b8bd" - integrity sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A== +"@vitest/snapshot@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470" + integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ== dependencies: magic-string "^0.30.5" pathe "^1.1.1" @@ -3361,10 +3400,10 @@ dependencies: tinyspy "^2.2.0" -"@vitest/spy@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.4.0.tgz#cf953c93ae54885e801cbe6b408a547ae613f26c" - integrity sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q== +"@vitest/spy@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.0.tgz#362cbd42ccdb03f1613798fde99799649516906d" + integrity sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw== dependencies: tinyspy "^2.2.0" @@ -3378,24 +3417,85 @@ loupe "^2.3.7" pretty-format "^29.7.0" -"@vitest/utils@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.4.0.tgz#ea6297e0d329f9ff0a106f4e1f6daf3ff6aad3f0" - integrity sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg== +"@vitest/utils@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.0.tgz#5c5675ca7d6f546a7b4337de9ae882e6c57896a1" + integrity sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw== dependencies: diff-sequences "^29.6.3" estree-walker "^3.0.3" loupe "^2.3.7" pretty-format "^29.7.0" -"@wdio/config@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.34.0.tgz#e4ee475ebed95a4d262b27204e2b854d6a508825" - integrity sha512-dtVGW/QEqM/WLUEZvca09y12L+hMZnzuwGuSzdG8B3wT6OaT+lSktU842HqHPC7OnZ27kRORhDJM6JLDy1T7dw== +"@volar/language-core@1.11.1", "@volar/language-core@~1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-1.11.1.tgz#ecdf12ea8dc35fb8549e517991abcbf449a5ad4f" + integrity sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw== + dependencies: + "@volar/source-map" "1.11.1" + +"@volar/source-map@1.11.1", "@volar/source-map@~1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-1.11.1.tgz#535b0328d9e2b7a91dff846cab4058e191f4452f" + integrity sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg== + dependencies: + muggle-string "^0.3.1" + +"@volar/typescript@~1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-1.11.1.tgz#ba86c6f326d88e249c7f5cfe4b765be3946fd627" + integrity sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ== + dependencies: + "@volar/language-core" "1.11.1" + path-browserify "^1.0.1" + +"@vue/compiler-core@3.4.23": + version "3.4.23" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.23.tgz#a08f5998e391ad75e602a66dd7255af9054df2f3" + integrity sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ== + dependencies: + "@babel/parser" "^7.24.1" + "@vue/shared" "3.4.23" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.0" + +"@vue/compiler-dom@^3.3.0": + version "3.4.23" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.23.tgz#6fa622d1e5c8508551564c5dc5948e9cddf60867" + integrity sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw== + dependencies: + "@vue/compiler-core" "3.4.23" + "@vue/shared" "3.4.23" + +"@vue/language-core@1.8.27", "@vue/language-core@^1.8.27": + version "1.8.27" + resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.27.tgz#2ca6892cb524e024a44e554e4c55d7a23e72263f" + integrity sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA== + dependencies: + "@volar/language-core" "~1.11.1" + "@volar/source-map" "~1.11.1" + "@vue/compiler-dom" "^3.3.0" + "@vue/shared" "^3.3.0" + computeds "^0.0.1" + minimatch "^9.0.3" + muggle-string "^0.3.1" + path-browserify "^1.0.1" + vue-template-compiler "^2.7.14" + +"@vue/shared@3.4.23", "@vue/shared@^3.3.0": + version "3.4.23" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.23.tgz#e536a6dfd2f5f950d08c2e8ebcfe7e5329a851a1" + integrity sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg== + +"@wdio/config@8.36.1": + version "8.36.1" + resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.36.1.tgz#150cd4477ef5e77c06fb752e0128342193ef1dc4" + integrity sha512-yCENnym0CrYuLKMJ3fv00WkjCR8QpPqVohGBkq5FvZOZpVJEpoG86Q8l4HtyRnd6ggMTKCA1vTQ/myhbPmZmaQ== dependencies: "@wdio/logger" "8.28.0" - "@wdio/types" "8.32.4" - "@wdio/utils" "8.33.1" + "@wdio/types" "8.36.1" + "@wdio/utils" "8.36.1" decamelize "^6.0.0" deepmerge-ts "^5.0.0" glob "^10.2.2" @@ -3433,21 +3533,21 @@ dependencies: "@types/node" "^20.1.0" -"@wdio/types@8.32.4": - version "8.32.4" - resolved "https://registry.yarnpkg.com/@wdio/types/-/types-8.32.4.tgz#cc1965d5a802a09696b1ea9066e8b92f6977d51a" - integrity sha512-pDPGcCvq0MQF8u0sjw9m4aMI2gAKn6vphyBB2+1IxYriL777gbbxd7WQ+PygMBvYVprCYIkLPvhUFwF85WakmA== +"@wdio/types@8.36.1": + version "8.36.1" + resolved "https://registry.yarnpkg.com/@wdio/types/-/types-8.36.1.tgz#5fa8dc05c0ce416b11b7a073fee0f319f533a70f" + integrity sha512-kKtyJbypasKo/VQuJ6dTQQwFtHE9qoygjoCZjrQCLGraRSjOEiqZHPR0497wbeCvcgHIYyImbmcylqZNGUE0CQ== dependencies: "@types/node" "^20.1.0" -"@wdio/utils@8.33.1": - version "8.33.1" - resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.33.1.tgz#8ab0679d5214d9a4bea4aa198d3c1a806d386df0" - integrity sha512-W0ArrZbs4M23POv8+FPsgHDFxg+wwklfZgLSsjVq2kpCmBCfIPxKSAOgTo/XrcH4We/OnshgBzxLcI+BHDgi4w== +"@wdio/utils@8.36.1": + version "8.36.1" + resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.36.1.tgz#b6b1e00c45963d1be8c7a9a65d90f7eeb65d6dbf" + integrity sha512-xmgPHU11/o9n2FeRmDFkPRC0okiwA1i2xOcR2c3aSpuk99XkAm9RaMn/6u9LFaqsCpgaVxazcYEGSceO7U4hZA== dependencies: "@puppeteer/browsers" "^1.6.0" "@wdio/logger" "8.28.0" - "@wdio/types" "8.32.4" + "@wdio/types" "8.36.1" decamelize "^6.0.0" deepmerge-ts "^5.1.0" edgedriver "^5.3.5" @@ -3512,18 +3612,6 @@ abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: module-error "^1.0.1" queue-microtask "^1.2.3" -abstract-leveldown@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" - integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== - dependencies: - buffer "^6.0.3" - catering "^2.0.0" - is-buffer "^2.0.5" - level-concat-iterator "^3.0.0" - level-supports "^2.0.1" - queue-microtask "^1.2.3" - abstract-logging@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" @@ -3607,7 +3695,7 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv@^6.12.4: +ajv@^6.12.4, ajv@~6.12.6: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -3791,7 +3879,7 @@ arg@^4.1.0: resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: +argparse@^1.0.7, argparse@~1.0.9: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4339,13 +4427,6 @@ buffer-xor@^1.0.3: resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= -buffer-xor@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-2.0.2.tgz" - integrity sha512-eHslX0bin3GB+Lx2p7lEYRShRewuNZL3fUl4qlVJGGiwoPGftmt8JQgk2Y9Ji5/01TnVDo33E5b5O3vUB1HdqQ== - dependencies: - safe-buffer "^5.1.1" - buffer@4.9.2, buffer@^4.3.0: version "4.9.2" resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz" @@ -4567,7 +4648,7 @@ case@^1.6.3: resolved "https://registry.npmjs.org/case/-/case-1.6.3.tgz" integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== -catering@^2.0.0, catering@^2.1.0, catering@^2.1.1: +catering@^2.1.0, catering@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== @@ -4692,15 +4773,15 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -classic-level@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" - integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== +classic-level@^1.2.0, classic-level@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.4.1.tgz#169ecf9f9c6200ad42a98c8576af449c1badbaee" + integrity sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ== dependencies: abstract-level "^1.0.2" catering "^2.1.0" module-error "^1.0.1" - napi-macros "~2.0.0" + napi-macros "^2.2.2" node-gyp-build "^4.3.0" clean-stack@^2.0.0: @@ -4859,6 +4940,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + commander@^9.3.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" @@ -4903,6 +4989,11 @@ compress-commons@^6.0.2: normalize-path "^3.0.0" readable-stream "^4.0.0" +computeds@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/computeds/-/computeds-0.0.1.tgz#215b08a4ba3e08a11ff6eee5d6d8d7166a97ce2e" + integrity sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -5013,11 +5104,6 @@ conventional-recommended-bump@7.0.1: git-semver-tags "^5.0.0" meow "^8.1.2" -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - cookie@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" @@ -5214,24 +5300,23 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -datastore-core@^9.0.0, datastore-core@^9.0.1, datastore-core@^9.1.1: - version "9.2.7" - resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-9.2.7.tgz#25d0773a56f6c6d4e475d850c550a09672171242" - integrity sha512-S5ADNGRy1p6kHT6Khld+FThe1ITHuUiyYQ84VX2Kv8s6cXDiUuLlYPBIbZaWIgqR/JwxQCwa+5/08w6BZSIAow== +datastore-core@^9.0.0, datastore-core@^9.1.1, datastore-core@^9.2.9: + version "9.2.9" + resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-9.2.9.tgz#74b4dd53d4597b59038488ba5f92a7f81769f8df" + integrity sha512-wraWTPsbtdE7FFaVo3pwPuTB/zXsgwGGAm8BgBYwYAuzZCTS0MfXmd/HH1vR9s0/NFFjOVmBkGiWCvKxZ+QjVw== dependencies: - "@libp2p/logger" "^4.0.1" + "@libp2p/logger" "^4.0.6" err-code "^3.0.1" + interface-datastore "^8.0.0" interface-store "^5.0.0" - it-all "^3.0.1" - it-drain "^3.0.1" - it-filter "^3.0.0" - it-map "^3.0.1" - it-merge "^3.0.1" - it-pipe "^3.0.0" - it-pushable "^3.0.0" - it-sort "^3.0.1" - it-take "^3.0.1" - uint8arrays "^5.0.0" + it-drain "^3.0.5" + it-filter "^3.0.4" + it-map "^3.0.5" + it-merge "^3.0.3" + it-pipe "^3.0.1" + it-pushable "^3.2.3" + it-sort "^3.0.4" + it-take "^3.0.4" datastore-level@*, datastore-level@^10.1.1: version "10.1.1" @@ -5251,6 +5336,11 @@ dateformat@^3.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== + debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -5434,10 +5524,10 @@ devtools-protocol@0.0.1147663: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz#4ec5610b39a6250d1f87e6b9c7e16688ed0ac78e" integrity sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ== -devtools-protocol@^0.0.1263784: - version "0.0.1263784" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1263784.tgz#fffc6860ac1afc46c4495e8b888ba50adb116bf3" - integrity sha512-k0SCZMwj587w4F8QYbP5iIbSonL6sd3q8aVJch036r9Tv2t9b5/Oq7AiJ/FJvRuORm/pJNXZtrdNNWlpRnl56A== +devtools-protocol@^0.0.1282316: + version "0.0.1282316" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1282316.tgz#4b398549e48251a09bbad7056578f7ad376f9b81" + integrity sha512-i7eIqWdVxeXBY/M+v83yRkOV1sTHnr3XYiC0YNBivLIE6hBfE2H0c2o8VC5ynT44yjy+Ei0kLrBQFK/RUKaAHQ== dezalgo@^1.0.4: version "1.0.4" @@ -5478,7 +5568,7 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dns-over-http-resolver@^2.1.1, dns-over-http-resolver@^3.0.2: +dns-over-http-resolver@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-2.1.3.tgz#bb7f2e10cc18d960339a6e30e21b8c1d99be7b38" integrity sha512-zjRYFhq+CsxPAouQWzOsxNMvEN+SHisjzhX8EMxd2Y0EG3thvn6wXQgMJLnTDImkhe4jhLbOQpXtL10nALBOSA== @@ -5488,13 +5578,20 @@ dns-over-http-resolver@^2.1.1, dns-over-http-resolver@^3.0.2: receptacle "^1.3.2" undici "^5.12.0" -dns-packet@^5.2.2, dns-packet@^5.4.0: +dns-packet@^5.2.2: version "5.6.0" resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +dns-packet@^5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f" + integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + docker-compose@^0.24.2: version "0.24.2" resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.24.2.tgz#172027153b6c16239d5457fe48f56c7803f42c9d" @@ -5605,9 +5702,9 @@ edgedriver@^5.3.5: which "^4.0.0" ejs@^3.1.7: - version "3.1.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" - integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== dependencies: jake "^10.8.5" @@ -5677,7 +5774,7 @@ enquirer@~2.3.6: dependencies: ansi-colors "^4.1.1" -entities@^4.4.0: +entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -6141,7 +6238,7 @@ event-target-shim@^5.0.0: resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: +eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -6347,10 +6444,10 @@ fastify-plugin@^4.0.0: resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-4.5.0.tgz#8b853923a0bba6ab6921bb8f35b81224e6988d91" integrity sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg== -fastify@^4.26.2: - version "4.26.2" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-4.26.2.tgz#9389595c46e9f4648de5bf8175e750bf32fed5a1" - integrity sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug== +fastify@^4.27.0: + version "4.27.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-4.27.0.tgz#e4a9b2a0a7b9efaeaf1140d47fdd4f91b5fcacb1" + integrity sha512-ci9IXzbigB8dyi0mSy3faa3Bsj0xWAPb9JeT4KRzubdSb6pNhcADRUaXCBml6V1Ss/a05kbtQls5LBmhHydoTA== dependencies: "@fastify/ajv-compiler" "^3.5.0" "@fastify/error" "^3.4.0" @@ -6361,7 +6458,7 @@ fastify@^4.26.2: fast-json-stringify "^5.8.0" find-my-way "^8.0.0" light-my-request "^5.11.0" - pino "^8.17.0" + pino "^9.0.0" process-warning "^3.0.0" proxy-addr "^2.0.7" rfdc "^1.3.0" @@ -6620,6 +6717,15 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@~7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -6746,11 +6852,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-iterator@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/get-iterator/-/get-iterator-1.0.2.tgz" - integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== - get-iterator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-2.0.1.tgz#a904829f61bace789e0d64bd1a504c511a015c3f" @@ -7142,6 +7243,11 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hashlru@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/hashlru/-/hashlru-2.3.0.tgz#5dc15928b3f6961a2056416bb3a4910216fdfb51" + integrity sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A== + hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -7149,7 +7255,7 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" -he@1.2.0: +he@1.2.0, he@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -7378,6 +7484,11 @@ import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-lazy@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + import-local@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -7489,13 +7600,13 @@ inquirer@^9.1.5: through "^2.3.6" wrap-ansi "^8.1.0" -interface-datastore@^8.0.0, interface-datastore@^8.2.0, interface-datastore@^8.2.7: - version "8.2.10" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.10.tgz#2d7fc026c8185378c4d3433fe942d9d6838f95cb" - integrity sha512-D8RuxMdjOPB+j6WMDJ+I2aXTDzUT6DIVjgzo1E+ODL7w8WrSFl9FXD2SYmgj6vVzdb7Kb5qmAI9pEnDZJz7ifg== +interface-datastore@^8.0.0, interface-datastore@^8.2.11, interface-datastore@^8.2.7: + version "8.2.11" + resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.11.tgz#1d555ce6218ab6cba6291fc361debe9713590207" + integrity sha512-9E0iXehfp/j0UbZ2mvlYB4K9pP7uQBCppfuy8WHs1EHF6wLQrM9+zwyX+8Qt6HnH4GKZRyXX/CNXm6oD4+QYgA== dependencies: interface-store "^5.0.0" - uint8arrays "^5.0.0" + uint8arrays "^5.0.2" interface-store@^5.0.0: version "5.1.0" @@ -7516,11 +7627,6 @@ ip-regex@^2.1.0: resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-5.0.0.tgz#cd313b2ae9c80c07bd3851e12bf4fa4dc5480632" - integrity sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw== - ip@^1.1.8: version "1.1.9" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" @@ -7536,11 +7642,6 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -ipaddr.js@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" - integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== - is-arguments@^1.0.4: version "1.1.0" resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz" @@ -7606,7 +7707,7 @@ is-ci@3.0.1: dependencies: ci-info "^3.2.0" -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.3.0, is-core-module@^2.5.0, is-core-module@^2.8.1: +is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.3.0, is-core-module@^2.5.0, is-core-module@^2.8.1: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== @@ -7667,10 +7768,10 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-loopback-addr@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-loopback-addr/-/is-loopback-addr-2.0.1.tgz#0b43534f0b16ff899f1f19f322b59c38bd25fa03" - integrity sha512-SEsepLbdWFb13B6U0tt6dYcUM0iK/U7XOC43N70Z4Qb88WpNtp+ospyNI9ddpqncs7Z7brAEsVBTQpaqSNntIw== +is-loopback-addr@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-loopback-addr/-/is-loopback-addr-2.0.2.tgz#70a6668fa3555d47caebdcee045745ab80adf5e4" + integrity sha512-26POf2KRCno/KTNL5Q0b/9TYnL00xEsSaLfiFRmjM7m7Lw7ZMmFybzzuX4CcsLAluZGd+niLUiMRxEooVE3aqg== is-my-ip-valid@^1.0.0: version "1.0.1" @@ -7920,7 +8021,7 @@ istanbul-reports@^3.1.6: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -it-all@^3.0.0, it-all@^3.0.1, it-all@^3.0.2, it-all@^3.0.4: +it-all@^3.0.0, it-all@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.4.tgz#08f2e3eb3df04fa4525a343dcacfbdf91ffee162" integrity sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ== @@ -7934,36 +8035,36 @@ it-byte-stream@^1.0.0: it-stream-types "^2.0.1" uint8arraylist "^2.4.1" -it-drain@^3.0.1, it-drain@^3.0.3: - version "3.0.5" - resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-3.0.5.tgz#d7aed18a16a12c157fa477653fb42c1b4f08491c" - integrity sha512-qYFe4SWdvs9oJGUY5bSjvmiLUMLzFEODNOQUdYdCIkuIgQF+AUB2INhM4yQ09buJ2rhHKDFxvTD/+yUq6qg0XA== +it-drain@^3.0.3, it-drain@^3.0.5: + version "3.0.7" + resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-3.0.7.tgz#671a5d0220802c5bce9e68fc2b07088540fbc674" + integrity sha512-vy6S1JKjjHSIFHgBpLpD1zhkCRl3z1zYWUxE14+kAYf+BL9ssWSFImJfhl361IIcwr0ofw8etzg11VqqB+ntUA== -it-filter@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-filter/-/it-filter-3.0.2.tgz#19ddf6185ea21d417e6075d5796c799fa2633b69" - integrity sha512-Hhzp5anX7tmKOBqTPasBYTPlq7l4Xk4lMBfLB5GfKZnL9WCc6pr8M9Waud4nHh3s9neb4xwDWk7KQsEapgWyJw== +it-filter@^3.0.0, it-filter@^3.0.4: + version "3.1.0" + resolved "https://registry.yarnpkg.com/it-filter/-/it-filter-3.1.0.tgz#16e2914f7f54de44a19c03eb8289027643f33a1b" + integrity sha512-FiYuzdsUhmMZJTJQ8YLdgX3ArjQmAtCG1lyrtZd+92/2eC6YO9UoybdrwVj/yyZkuXAPykrSipLuZ+KSKpt29A== dependencies: it-peekable "^3.0.0" -it-foreach@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.0.3.tgz#40c96680d9875805203f61fdd1064b7190a17e5a" - integrity sha512-rpkhyHMSSe9pkmTtPcDoA5+NKhMUDqddwdXakUzNn/aOIp3vNnGBH4P4xncefxZM29iwzKBnK7AGcYVYoIG8gQ== +it-foreach@^2.0.6: + version "2.1.0" + resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.1.0.tgz#37dd606d92d93ac82ee3fdeffeec7f9f8dd76cf8" + integrity sha512-nobWUecq9E2ED1kcXz2o27yN6KePauSdmxJNMwCduWByrF4WNB2UgBHjr9QV2jPXpEWPDuzxZas9fVhQj1Vovg== dependencies: it-peekable "^3.0.0" -it-length-prefixed-stream@^1.0.0, it-length-prefixed-stream@^1.1.1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.1.6.tgz#b757b96d352da6e97b66002dd2ead32893ba2337" - integrity sha512-MEby4r8n3XIYXjaWT3DweCuhBPQmFVT8RdI1BNjYQ5gelbFD3NLdjYpTI3TVmSEs/aJfgpfVFZzy6iP7OCxIgw== +it-length-prefixed-stream@^1.0.0, it-length-prefixed-stream@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.1.7.tgz#de4fec7da005f9a593e3eccd901c183154be09f9" + integrity sha512-tH38h/wChpR6As/PD6yWZlpoMuB4wDW2Rxf3QbSt4+O1HTsLYbyZasNhTyIuvQqhebQ30OYrdM0yr9ig5qUvYQ== dependencies: it-byte-stream "^1.0.0" it-stream-types "^2.0.1" - uint8-varint "^2.0.1" - uint8arraylist "^2.4.1" + uint8-varint "^2.0.4" + uint8arraylist "^2.4.8" -it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.3, it-length-prefixed@^9.0.4: +it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.4: version "9.0.4" resolved "https://registry.yarnpkg.com/it-length-prefixed/-/it-length-prefixed-9.0.4.tgz#8096c3270420fe8abaa920c7b4d5e5895144008e" integrity sha512-lz28fykbG0jq7s5XtvlzGxO5BeSOw6ikymkRllxjL21V5VKLcvB4pHr9wPvEnsAJ2et1xpOk3BRTMq9XrhgKsg== @@ -7975,19 +8076,19 @@ it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.3, it-length-prefixed@^9.0.4: uint8arraylist "^2.0.0" uint8arrays "^5.0.1" -it-map@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/it-map/-/it-map-3.0.3.tgz#42be39fc68dc9b0d70cfd8ac4b8311d4b5cd7f22" - integrity sha512-Yf89GJYeYUZb2NZzWkvFHm3IBXlxro74i2vGRmpf8BYau3BhlaS37ieDenJEdYzkTGJhL/EbM1jPPw/KGVVVIw== +it-map@^3.0.1, it-map@^3.0.5: + version "3.1.0" + resolved "https://registry.yarnpkg.com/it-map/-/it-map-3.1.0.tgz#a66e5447d2ed8167ff90d19b183f6a3f8ae6e1b9" + integrity sha512-B7zNmHYRE0qes8oTiNYU7jXEF5WvKZNAUosskCks1JT9Z4DNwRClrQyd+C/hgITG8ewDbVZMGx9VXAx3KMY2kA== dependencies: it-peekable "^3.0.0" -it-merge@^3.0.0, it-merge@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/it-merge/-/it-merge-3.0.3.tgz#c7d407c8e0473accf7f9958ce2e0f60276002e84" - integrity sha512-FYVU15KC5pb/GQX1Ims+lee8d4pdqGVCpWr0lkNj8o4xuNo7jY71k6GuEiWdP+T7W1bJqewSxX5yoTy5yZpRVA== +it-merge@^3.0.0, it-merge@^3.0.3: + version "3.0.5" + resolved "https://registry.yarnpkg.com/it-merge/-/it-merge-3.0.5.tgz#2b0d1d07c825b9d20c4c2889aab8e07322fd803e" + integrity sha512-2l7+mPf85pyRF5pqi0dKcA54E5Jm/2FyY5GsOaN51Ta0ipC7YZ3szuAsH8wOoB6eKY4XsU4k2X+mzPmFBMayEA== dependencies: - it-pushable "^3.2.0" + it-pushable "^3.2.3" it-pair@^2.0.6: version "2.0.6" @@ -8009,7 +8110,7 @@ it-peekable@^3.0.0: resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-3.0.1.tgz#530953f735359c10503e961c059602f8a366a1a5" integrity sha512-5zBfkf6e+YoxxWV0YDXMwdQKnc7eeTX6xo3WYPm/8dIoctIiDnddInRWOW+83W/8/76sbnpWqqsO4gSyXandeQ== -it-pipe@^3.0.0, it-pipe@^3.0.1: +it-pipe@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/it-pipe/-/it-pipe-3.0.1.tgz#b25720df82f4c558a8532602b5fbc37bbe4e7ba5" integrity sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA== @@ -8018,17 +8119,16 @@ it-pipe@^3.0.0, it-pipe@^3.0.1: it-pushable "^3.1.2" it-stream-types "^2.0.1" -it-protobuf-stream@^1.0.2, it-protobuf-stream@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.1.2.tgz#4444d78fcae0fce949b4cbea622bf1d92667e64f" - integrity sha512-epZBuG+7cPaTxCR/Lf3ApshBdA9qfflGPQLfLLrp9VQ0w67Z2xo4H+SLLetav57/29oPtAXwVaoyemg99JOWzA== +it-protobuf-stream@^1.1.1, it-protobuf-stream@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.1.3.tgz#66d95ad55b66827fbd057e45bd411917437bc116" + integrity sha512-96n+e6X8CXL0JerxTJuEnfivmfLzGKpIGAlJLoH7HEGo2nPRrMe+HxeWGwDF4Un3FphI/Z62JNxSvq/5DxfiQw== dependencies: it-length-prefixed-stream "^1.0.0" it-stream-types "^2.0.1" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.1" + uint8arraylist "^2.4.8" -it-pushable@^3.0.0, it-pushable@^3.1.2, it-pushable@^3.2.0, it-pushable@^3.2.1, it-pushable@^3.2.3: +it-pushable@^3.1.2, it-pushable@^3.2.0, it-pushable@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/it-pushable/-/it-pushable-3.2.3.tgz#e2b80aed90cfbcd54b620c0a0785e546d4e5f334" integrity sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg== @@ -8043,10 +8143,10 @@ it-reader@^6.0.1: it-stream-types "^2.0.1" uint8arraylist "^2.0.0" -it-sort@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-sort/-/it-sort-3.0.2.tgz#5bf8549b74c74aee20636184791941413b09abf7" - integrity sha512-gRvHyXkn13hyXIoiGkvg7Mf1Yg8JUB+ArKjMrGCYfd/4MQ8mQlMCOE6H8itjshwdVEAUDrppb786zODndYyjSg== +it-sort@^3.0.1, it-sort@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/it-sort/-/it-sort-3.0.5.tgz#7209710c64e83e130659e00b2e42df4b36643f7e" + integrity sha512-vFo3wYR+aRDwklp8iH8LKeePmWqXGQrS8JqEdZmbJ58DIGj67n0RT/t5BR8iYps/C/v5IdWsbow1bOCEUfY+hA== dependencies: it-all "^3.0.0" @@ -8055,10 +8155,10 @@ it-stream-types@^2.0.1: resolved "https://registry.yarnpkg.com/it-stream-types/-/it-stream-types-2.0.1.tgz#69cb4d7e79e707b8257a8997e02751ccb6c3af32" integrity sha512-6DmOs5r7ERDbvS4q8yLKENcj6Yecr7QQTqWApbZdfAUTEC947d+PEha7PCqhm//9oxaLYL7TWRekwhoXl2s6fg== -it-take@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-take/-/it-take-3.0.2.tgz#ba947c6300a36556e223b4f5ab0bffba4b4fbbb1" - integrity sha512-HgtnQYW45iV+lOJIk54dhKWNi+puAeutUehIWQE9tRkM91nlCn0abbDU2xG/FZV3cVnEG4hGwxOEImnMMKwhmg== +it-take@^3.0.1, it-take@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/it-take/-/it-take-3.0.5.tgz#c5a82cb160d5d7767954d84c6ce30d680f884b77" + integrity sha512-4CzqXzx7FAeXsRYBTH0GhkxerH8Sv0nEGIXrO0ZIpECHth59Dm9ZYZ161VPrCQccWIL/Vu6M9YptlbMiEpCIlQ== jackspeak@^2.0.3: version "2.3.3" @@ -8103,6 +8203,11 @@ jest-get-type@^29.6.3: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + jmespath@0.15.0: version "0.15.0" resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz" @@ -8286,6 +8391,11 @@ kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + kuler@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" @@ -8384,18 +8494,6 @@ lerna@^7.3.0: yargs "16.2.0" yargs-parser "20.2.4" -level-concat-iterator@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" - integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== - dependencies: - catering "^2.1.0" - -level-supports@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" - integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== - level-supports@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" @@ -8417,15 +8515,6 @@ level@^8.0.0: browser-level "^1.0.1" classic-level "^1.2.0" -leveldown@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.1.tgz#0f0e480fa88fd807abf94c33cb7e40966ea4b5ce" - integrity sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A== - dependencies: - abstract-leveldown "^7.2.0" - napi-macros "~2.0.0" - node-gyp-build "^4.3.0" - levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -8456,32 +8545,32 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -libp2p@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-1.1.1.tgz#a57f4793ee87a0eba67a3f039724c79ad1b24224" - integrity sha512-577X5MPRH5vhJzWPLNbXg5EdWNuTzZG90HHTaCFGdrzYLyrGcQWb4RK4Ji3dZALYmx6NmuwTkZv5oojnu2ayng== - dependencies: - "@libp2p/crypto" "^3.0.4" - "@libp2p/interface" "^1.1.1" - "@libp2p/interface-internal" "^1.0.5" - "@libp2p/logger" "^4.0.4" - "@libp2p/multistream-select" "^5.1.1" - "@libp2p/peer-collections" "^5.1.3" - "@libp2p/peer-id" "^4.0.4" - "@libp2p/peer-id-factory" "^4.0.3" - "@libp2p/peer-store" "^10.0.5" - "@libp2p/utils" "^5.2.0" - "@multiformats/multiaddr" "^12.1.10" +libp2p@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-1.4.3.tgz#830453eec2982e5c0faf79558a0aaa87d1e5b150" + integrity sha512-/J+bqE+bYw6iiyPBlBZk1PrZo182f9W1zSzWcMrNy+CQCG/WdJllft/WxvhNKHK1KuIS/JsL9gvhuRhtpqmMKg== + dependencies: + "@libp2p/crypto" "^4.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/interface-internal" "^1.1.1" + "@libp2p/logger" "^4.0.11" + "@libp2p/multistream-select" "^5.1.8" + "@libp2p/peer-collections" "^5.1.11" + "@libp2p/peer-id" "^4.1.0" + "@libp2p/peer-id-factory" "^4.1.0" + "@libp2p/peer-store" "^10.0.16" + "@libp2p/utils" "^5.3.2" + "@multiformats/dns" "^1.0.5" + "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr-matcher" "^1.2.0" any-signal "^4.1.1" - datastore-core "^9.0.1" - interface-datastore "^8.2.0" - it-merge "^3.0.0" + datastore-core "^9.2.9" + interface-datastore "^8.2.11" + it-merge "^3.0.3" it-parallel "^3.0.6" merge-options "^3.0.4" - multiformats "^13.0.0" - private-ip "^3.0.1" - rate-limiter-flexible "^4.0.0" - uint8arrays "^5.0.0" + multiformats "^13.1.0" + uint8arrays "^5.0.3" light-my-request@^5.11.0: version "5.12.0" @@ -8603,6 +8692,16 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" @@ -8648,7 +8747,7 @@ lodash.zip@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" integrity sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg== -lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.21, lodash@~4.17.15: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8691,11 +8790,6 @@ loglevel@^1.6.0: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== -long@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" - integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== - loupe@^2.3.6, loupe@^2.3.7: version "2.3.6" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" @@ -8744,6 +8838,13 @@ magic-string@^0.30.3, magic-string@^0.30.5: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" +magic-string@^0.30.8: + version "0.30.10" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" + integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + magicast@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.3.tgz#a15760f982deec9dabc5f314e318d7c6bddcb27b" @@ -9054,6 +9155,20 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimatch@~3.0.3: + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -9248,14 +9363,13 @@ moment@^2.29.1: resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== -mortice@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mortice/-/mortice-3.0.1.tgz#27c1943b1841502c7b27a9c8fea789f87c124515" - integrity sha512-eyDUsl1nCR9+JtNksKnaESLP9MgAXCA4w1LTtsmOSQNsThnv++f36rrBu5fC/fdGIwTJZmbiaR/QewptH93pYA== +mortice@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/mortice/-/mortice-3.0.4.tgz#34aadef768161e9dc49a7f73637b7858bcb7c6fa" + integrity sha512-MUHRCAztSl4v/dAmK8vbYi5u1n9NZtQu4H3FsqS7qgMFQIAFw9lTpHiErd9kJpapqmvEdD1L3dUmiikifAvLsQ== dependencies: - nanoid "^4.0.0" observable-webworkers "^2.0.1" - p-queue "^7.2.0" + p-queue "^8.0.1" p-timeout "^6.0.0" mrmime@^2.0.0: @@ -9273,6 +9387,11 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +muggle-string@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.3.1.tgz#e524312eb1728c63dd0b2ac49e3282e6ed85963a" + integrity sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg== + multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" @@ -9286,15 +9405,10 @@ multiformats@^11.0.1: resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-11.0.2.tgz#b14735efc42cd8581e73895e66bebb9752151b60" integrity sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg== -multiformats@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-12.0.1.tgz#dd3e19dd44114c2672e4795a36888d263be30131" - integrity sha512-s01wijBJoDUqESWSzePY0lvTw7J3PVO9x2Cc6ASI5AMZM2Gnhh7BC17+nlFhHKU7dDzaCaRfb+NiqNzOsgPUoQ== - -multiformats@^13.0.0, multiformats@^13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.0.1.tgz#c0622affa5171189eacd57c06f977195ca7acb08" - integrity sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA== +multiformats@^13.0.0, multiformats@^13.0.1, multiformats@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.1.0.tgz#5aa9d2175108a448fc3bdb54ba8a3d0b6cab3ac3" + integrity sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ== multimatch@5.0.0: version "5.0.0" @@ -9322,10 +9436,10 @@ n12@0.4.0: resolved "https://registry.yarnpkg.com/n12/-/n12-0.4.0.tgz#363058560b435e6857b5e039ed5eab08c5122e5e" integrity sha512-p/hj4zQ8d3pbbFLQuN1K9honUxiDDhueOWyFLw/XgBv+wZCE44bcLH4CIcsolOceJQduh4Jf7m/LfaTxyGmGtQ== -nan@^2.16.0, nan@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nan@^2.16.0, nan@^2.17.0, nan@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== nanoid@3.3.3: version "3.3.3" @@ -9337,15 +9451,10 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== -nanoid@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" - integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== - -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== +napi-macros@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" + integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== native-fetch@^4.0.2: version "4.0.2" @@ -9415,11 +9524,6 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-forge@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - node-gyp-build@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" @@ -9962,10 +10066,10 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== -p-defer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-4.0.0.tgz#8082770aeeb10eb6b408abe91866738741ddd5d2" - integrity sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ== +p-defer@^4.0.0, p-defer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-4.0.1.tgz#d12c6d41420785ed0d162dbd86b71ba490f7f99e" + integrity sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A== p-finally@^1.0.0: version "1.0.0" @@ -10060,15 +10164,7 @@ p-queue@6.6.2: eventemitter3 "^4.0.4" p-timeout "^3.2.0" -p-queue@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.2.0.tgz#e1430e4432f09b43aa8b4913d4c2ff7fdd685479" - integrity sha512-Kvv7p13M46lTYLQ/PsZdaj/1Vj6u/8oiIJgyQyx4oVkOfHdd7M2EZvXigDvcsSzRwanCzQirV5bJPQFoSQt5MA== - dependencies: - eventemitter3 "^4.0.7" - p-timeout "^5.0.2" - -p-queue@^8.0.0: +p-queue@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-8.0.1.tgz#718b7f83836922ef213ddec263ff4223ce70bef8" integrity sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA== @@ -10088,11 +10184,6 @@ p-timeout@^3.2.0: dependencies: p-finally "^1.0.0" -p-timeout@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-5.1.0.tgz#b3c691cf4415138ce2d9cfe071dba11f0fee085b" - integrity sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew== - p-timeout@^6.0.0, p-timeout@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-6.1.2.tgz#22b8d8a78abf5e103030211c5fc6dee1166a6aa5" @@ -10269,7 +10360,7 @@ path-key@^4.0.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== -path-parse@^1.0.5, path-parse@^1.0.7: +path-parse@^1.0.5, path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -10355,10 +10446,10 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pino-abstract-transport@v1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz#083d98f966262164504afb989bccd05f665937a8" - integrity sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA== +pino-abstract-transport@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz#97f9f2631931e242da531b5c66d3079c12c9d1b5" + integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q== dependencies: readable-stream "^4.0.0" split2 "^4.0.0" @@ -10368,22 +10459,22 @@ pino-std-serializers@^6.0.0: resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.0.tgz#169048c0df3f61352fce56aeb7fb962f1b66ab43" integrity sha512-IWgSzUL8X1w4BIWTwErRgtV8PyOGOOi60uqv0oKuS/fOA8Nco/OeI6lBuc4dyP8MMfdFwyHqTMcBIA7nDiqEqA== -pino@^8.17.0: - version "8.19.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-8.19.0.tgz#ccc15ef736f103ec02cfbead0912bc436dc92ce4" - integrity sha512-oswmokxkav9bADfJ2ifrvfHUwad6MLp73Uat0IkQWY3iAw5xTRoznXbXksZs8oaOUMpmhVWD+PZogNzllWpJaA== +pino@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-9.0.0.tgz#25fddb6f449032afcc8c939c2234d4a24b9129a6" + integrity sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA== dependencies: atomic-sleep "^1.0.0" fast-redact "^3.1.1" on-exit-leak-free "^2.1.0" - pino-abstract-transport v1.1.0 + pino-abstract-transport "^1.2.0" pino-std-serializers "^6.0.0" process-warning "^3.0.0" quick-format-unescaped "^4.0.3" real-require "^0.2.0" safe-stable-stringify "^2.3.1" sonic-boom "^3.7.0" - thread-stream "^2.0.0" + thread-stream "^2.6.0" pkg-dir@^4.2.0: version "4.2.0" @@ -10443,16 +10534,6 @@ pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -private-ip@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/private-ip/-/private-ip-3.0.1.tgz#1fa8108f53512c6b82f79d4d2ac665140dee5da5" - integrity sha512-Ezc16ANuhSHmWAE6lbXUKburNzGpR0J5X0Zh5Um/PZ/s57Fp+HYqYe6BYPH2QbqKr/5WebfzJQ1jq6Kj5dbRmA== - dependencies: - "@chainsafe/is-ip" "^2.0.1" - ip-regex "^5.0.0" - ipaddr.js "^2.1.0" - netmask "^2.0.2" - proc-log@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" @@ -10483,10 +10564,10 @@ progress@2.0.3, progress@^2.0.3: resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@^15.0.0, prom-client@^15.1.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.0.tgz#816a4a2128da169d0471093baeccc6d2f17a4613" - integrity sha512-cCD7jLTqyPdjEPBo/Xk4Iu8jxjuZgZJ3e/oET3L+ZwOuap/7Cw3dH/TJSsZKs1TQLZ2IHpIlRAKw82ef06kmMw== +prom-client@^15.1.0, prom-client@^15.1.1: + version "15.1.2" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.2.tgz#78d79f12c35d395ca97edf7111c18210cf07f815" + integrity sha512-on3h1iXb04QFLLThrmVYg1SChBQ9N1c+nKAjebBjokBqipddH3uxmOUcEkTnzmJ8Jh/5TSUnUqS40i2QB2dJHQ== dependencies: "@opentelemetry/api" "^1.4.0" tdigest "^0.1.1" @@ -10527,36 +10608,19 @@ properties-reader@^2.2.0: dependencies: mkdirp "^1.0.4" -protobufjs@^7.0.0, protobufjs@^7.2.6: - version "7.2.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - protocols@^2.0.0, protocols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== -protons-runtime@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/protons-runtime/-/protons-runtime-5.0.0.tgz#1eb3c78637ff02cc90bb030e3bff6f0402109c25" - integrity sha512-QqjGnPGkpvbzq0dITzhG9DVK10rRIHf7nePcU2QQVVpFGuYbwrOWnvGSvei1GcceAzB9syTz6vHzvTPmGRR0PA== +protons-runtime@5.4.0, protons-runtime@^5.0.0, protons-runtime@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/protons-runtime/-/protons-runtime-5.4.0.tgz#2751ce22cae6c35eebba89acfd9d783419ae3726" + integrity sha512-XfA++W/WlQOSyjUyuF5lgYBfXZUEMP01Oh1C2dSwZAlF2e/ZrMRPfWonXj6BGM+o8Xciv7w0tsRMKYwYEuQvaw== dependencies: - protobufjs "^7.0.0" + uint8-varint "^2.0.2" uint8arraylist "^2.4.3" + uint8arrays "^5.0.1" proxy-addr@^2.0.7: version "2.0.7" @@ -10701,10 +10765,10 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -race-event@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/race-event/-/race-event-1.1.0.tgz#69c2d855653acf11d8b23ea8f6fa50e1180a088b" - integrity sha512-8BTiN6IAbov8mqkVEc3LiYbtUzanLfzFhwPF7kZV74ztYeQXdFPIgMCd/sy8xie6ZMtf2JPeMBedx78/RRNO3g== +race-event@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/race-event/-/race-event-1.3.0.tgz#854f34118c31addf877898bd9f8e4dcfac9de7a2" + integrity sha512-kaLm7axfOnahIqD3jQ4l1e471FIFcEGebXEnhxyLscuUzV8C94xVHtWEqDDXxll7+yu/6lW0w1Ff4HbtvHvOHg== race-signal@^1.0.2: version "1.0.2" @@ -10726,11 +10790,6 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -rate-limiter-flexible@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-4.0.0.tgz#4754706216f0b442e7527b1367e42b7682145010" - integrity sha512-SkA18LEPqJJKHixi6E7tzBKTXbj9gu5wPyfTykPVRZR5JGSw0dMCjtZsjlfuabVY940pu28Wu87NZN4FhztnyQ== - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -10938,7 +10997,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.17.0, resolve@^1.22.4: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.17.0, resolve@^1.22.4, resolve@~1.22.1: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -10947,6 +11006,14 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.17.0, resolve@^1.22.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@~1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + responselike@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" @@ -11071,6 +11138,16 @@ roarr@^2.15.3: semver-compare "^1.0.0" sprintf-js "^1.1.2" +rollup-plugin-visualizer@^5.12.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz#661542191ce78ee4f378995297260d0c1efb1302" + integrity sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ== + dependencies: + open "^8.4.0" + picomatch "^2.3.1" + source-map "^0.7.4" + yargs "^17.5.1" + rollup@^4.13.0: version "4.16.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.16.1.tgz#5a60230987fe95ebe68bab517297c116dbb1a88d" @@ -11227,7 +11304,7 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@7.6.0: +semver@7.6.0, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== @@ -11239,7 +11316,7 @@ semver@^6.1.0, semver@^6.2.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -11508,6 +11585,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -11672,12 +11754,12 @@ stream-http@^3.2.0: readable-stream "^3.6.0" xtend "^4.0.2" -stream-to-it@^0.2.2: - version "0.2.3" - resolved "https://registry.npmjs.org/stream-to-it/-/stream-to-it-0.2.3.tgz" - integrity sha512-xaK9EjPtLox5rrC7YLSBXSanTtUJN/lzJlMFvy9VaROmnyvy0U/X6m2uMhXPJRn3g3M9uOSIzTszW7BPiWSg9w== +stream-to-it@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-to-it/-/stream-to-it-1.0.1.tgz#7d5e1b04bab70facd48273279bfa49f0d0165950" + integrity sha512-AqHYAYPHcmvMrcLNgncE/q0Aj/ajP6A4qGhxP6EVn7K3YTNs0bJpJyk57wc2Heb7MUL64jurvmnmui8D9kjZgA== dependencies: - get-iterator "^1.0.2" + it-stream-types "^2.0.1" streamx@^2.13.0: version "2.16.1" @@ -11702,6 +11784,11 @@ 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-argv@~0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + "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" @@ -11827,7 +11914,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@3.1.1, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -11891,7 +11978,7 @@ supertest@^6.3.3: methods "^1.1.2" superagent "^8.0.5" -supports-color@8.1.1: +supports-color@8.1.1, supports-color@~8.1.1: version "8.1.1" resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -11930,10 +12017,10 @@ synckit@^0.8.6: "@pkgr/core" "^0.1.0" tslib "^2.6.2" -systeminformation@^5.17.12: - version "5.21.7" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.21.7.tgz#53ef75daaf5d756d015f4bb02e059126ccac74f2" - integrity sha512-K3LjnajrazTLTD61+87DFg8IXFk5ljx6nSBqB8pQLtC1UPivAjDtTYGPZ8jaBFxcesPaCOkvLRtBq+RFscrsLw== +systeminformation@^5.22.9: + version "5.22.9" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.22.9.tgz#68700a895a48cbf96e2cd6a34c5027d1fe58f053" + integrity sha512-qUWJhQ9JSBhdjzNUQywpvc0icxUAjMY3sZqUoS0GOtaJV9Ijq8s9zEP8Gaqmymn1dOefcICyPXK1L3kgKxlUpg== tapable@^2.2.0: version "2.2.1" @@ -12070,10 +12157,10 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -thread-stream@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.3.0.tgz#4fc07fb39eff32ae7bad803cb7dd9598349fed33" - integrity sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA== +thread-stream@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.7.0.tgz#d8a8e1b3fd538a6cca8ce69dbe5d3d097b601e11" + integrity sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw== dependencies: real-require "^0.2.0" @@ -12119,10 +12206,10 @@ tinypool@^0.8.1: resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.1.tgz#b6c4e4972ede3e3e5cda74a3da1679303d386b03" integrity sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg== -tinypool@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.2.tgz#84013b03dc69dacb322563a475d4c0a9be00f82a" - integrity sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ== +tinypool@^0.8.3: + version "0.8.4" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" + integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== tinyspy@^2.2.0: version "2.2.0" @@ -12226,6 +12313,11 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-node@^10.8.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -12456,16 +12548,16 @@ typescript-docs-verifier@^2.5.0: tsconfig "^7.0.0" yargs "^17.5.1" +typescript@5.4.2, typescript@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + "typescript@>=3 < 6": version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -typescript@^5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" - integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== - ufo@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" @@ -12476,10 +12568,10 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.2.tgz#f55f668b9a64b213977ae688703b6bbb7ca861c6" integrity sha512-bbxglRjsGQMchfvXZNusUcYgiB9Hx2K4AHYXQy2DITZ9Rd+JzhX7+hoocE5Winr7z2oHvPsekkBwXtigvxevXg== -uint8-varint@^2.0.0, uint8-varint@^2.0.1, uint8-varint@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uint8-varint/-/uint8-varint-2.0.3.tgz#049fceb3e870757dec26b29633770900f3132233" - integrity sha512-seXTM8ba4uuAMDgi3UHXPdDxCBKjWWZigW+F+1ESPhOZv9ekT1qmbdzYHLSNA+u+wHj10P55dQ41y2Qh7NOqiA== +uint8-varint@^2.0.1, uint8-varint@^2.0.2, uint8-varint@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/uint8-varint/-/uint8-varint-2.0.4.tgz#85be52b3849eb30f2c3640a2df8a14364180affb" + integrity sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw== dependencies: uint8arraylist "^2.0.0" uint8arrays "^5.0.0" @@ -12491,10 +12583,10 @@ uint8arraylist@^2.0.0, uint8arraylist@^2.4.1, uint8arraylist@^2.4.3, uint8arrayl dependencies: uint8arrays "^5.0.1" -uint8arrays@^5.0.0, uint8arrays@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.0.1.tgz#6016ef944379eabb6de605934ead4d7a698c9f07" - integrity sha512-ND5RpJAnPgHmZT7hWD/2T4BwRp04j8NLKvMKC/7bhiEwEjUMkQ4kvBKiH6hOqbljd6qJ2xS8reL3vl1e33grOQ== +uint8arrays@^5.0.0, uint8arrays@^5.0.1, uint8arrays@^5.0.2, uint8arrays@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.0.3.tgz#92b894d9c4269ba97c51544d6e1f279fe6f80d1f" + integrity sha512-6LBuKji28kHjgPJMkQ6GDaBb1lRwIhyOYq6pDGwYMoDPfImE9SkuYENVmR0yu9yGgs2clHUSY9fKDukR+AXfqQ== dependencies: multiformats "^13.0.0" @@ -12693,15 +12785,6 @@ v8-compile-cache@2.3.0: resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" - integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^2.0.0" - validate-npm-package-license@3.0.4, validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -12724,6 +12807,11 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +validator@^13.7.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + vite-node@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.1.tgz#bca96ae91b2b1ee9a7aa73685908362d70ce26a8" @@ -12735,10 +12823,10 @@ vite-node@1.2.1: picocolors "^1.0.0" vite "^5.0.0" -vite-node@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.4.0.tgz#265529d60570ca695ceb69391f87f92847934ad8" - integrity sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw== +vite-node@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f" + integrity sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw== dependencies: cac "^6.7.14" debug "^4.3.4" @@ -12746,6 +12834,19 @@ vite-node@1.4.0: picocolors "^1.0.0" vite "^5.0.0" +vite-plugin-dts@^3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz#625ad388ec3956708ccec7960550a7b0a8e8909e" + integrity sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg== + dependencies: + "@microsoft/api-extractor" "7.43.0" + "@rollup/pluginutils" "^5.1.0" + "@vue/language-core" "^1.8.27" + debug "^4.3.4" + kolorist "^1.8.0" + magic-string "^0.30.8" + vue-tsc "^1.8.27" + vite-plugin-node-polyfills@^0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.21.0.tgz#5566b3a725d4bbc75f4f794b0467e4047c14a58c" @@ -12763,10 +12864,10 @@ vite-plugin-top-level-await@^1.4.1: "@swc/core" "^1.3.100" uuid "^9.0.1" -vite@^5.0.0: - version "5.2.10" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.10.tgz#2ac927c91e99d51b376a5c73c0e4b059705f5bd7" - integrity sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw== +vite@^5.0.0, vite@^5.2.11: + version "5.2.11" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.11.tgz#726ec05555431735853417c3c0bfb36003ca0cbd" + integrity sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ== dependencies: esbuild "^0.20.1" postcss "^8.4.38" @@ -12806,16 +12907,16 @@ vitest@^1.2.1: vite-node "1.2.1" why-is-node-running "^2.2.2" -vitest@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.4.0.tgz#f5c812aaf5023818b89b7fc667fa45327396fece" - integrity sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw== - dependencies: - "@vitest/expect" "1.4.0" - "@vitest/runner" "1.4.0" - "@vitest/snapshot" "1.4.0" - "@vitest/spy" "1.4.0" - "@vitest/utils" "1.4.0" +vitest@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.0.tgz#9d5ad4752a3c451be919e412c597126cffb9892f" + integrity sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA== + dependencies: + "@vitest/expect" "1.6.0" + "@vitest/runner" "1.6.0" + "@vitest/snapshot" "1.6.0" + "@vitest/spy" "1.6.0" + "@vitest/utils" "1.6.0" acorn-walk "^8.3.2" chai "^4.3.10" debug "^4.3.4" @@ -12827,9 +12928,9 @@ vitest@^1.4.0: std-env "^3.5.0" strip-literal "^2.0.0" tinybench "^2.5.1" - tinypool "^0.8.2" + tinypool "^0.8.3" vite "^5.0.0" - vite-node "1.4.0" + vite-node "1.6.0" why-is-node-running "^2.2.2" vm-browserify@^1.0.1: @@ -12837,6 +12938,23 @@ vm-browserify@^1.0.1: resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== +vue-template-compiler@^2.7.14: + version "2.7.16" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b" + integrity sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ== + dependencies: + de-indent "^1.0.2" + he "^1.2.0" + +vue-tsc@^1.8.27: + version "1.8.27" + resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.27.tgz#feb2bb1eef9be28017bb9e95e2bbd1ebdd48481c" + integrity sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg== + dependencies: + "@volar/typescript" "~1.11.1" + "@vue/language-core" "1.8.27" + semver "^7.5.4" + w3c-xmlserializer@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" @@ -13100,40 +13218,40 @@ web3@^4.0.3: web3-utils "^4.0.3" web3-validator "^1.0.2" -webdriver@8.34.0: - version "8.34.0" - resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.34.0.tgz#32509b5aeb63e574f053c5c6eacff7f78748c6eb" - integrity sha512-r8oe6tIm2qSdLNhzwVpVMWJvuoZTbeTZI21+EidqZtp6krlnJzd+hIRD5ojTm+yYi86JlRQnMMQ40LUBsAGVsQ== +webdriver@8.36.1: + version "8.36.1" + resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.36.1.tgz#4e57a9bc50a7cf1398955b8426c99ac2f6e1f36c" + integrity sha512-547RivYCHStVqtiGQBBcABAkzJbPnAWsxpXGzmj5KL+TOM2JF41N2iQRtUxXqr0jme1Nzzye7WS7Y7iSnK6i1g== dependencies: "@types/node" "^20.1.0" "@types/ws" "^8.5.3" - "@wdio/config" "8.34.0" + "@wdio/config" "8.36.1" "@wdio/logger" "8.28.0" "@wdio/protocols" "8.32.0" - "@wdio/types" "8.32.4" - "@wdio/utils" "8.33.1" + "@wdio/types" "8.36.1" + "@wdio/utils" "8.36.1" deepmerge-ts "^5.1.0" got "^12.6.1" ky "^0.33.0" ws "^8.8.0" -webdriverio@^8.34.1: - version "8.34.1" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.34.1.tgz#1033c12d6d4ea410f92447b67cfc0bfdd0ac4796" - integrity sha512-9C+sy8mkvIGdKFFHL5oq6s2Uhq1lsAXybG3MsF0QA2822Jm+oYHN4KohrOGF0yBJc/x5JRaW3/hXvldnj7a55A== +webdriverio@^8.36.1: + version "8.36.1" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.36.1.tgz#67f6f5e7d383878910d51e8362b003bab45623c6" + integrity sha512-vzE09oFQeMbOYJ/75jZ13sDIljzC3HH7uoUJKAMAEtyrn/bu1F9Sg/4IDEsvQaRD3pz3ae6SkRld33lcQk6HJA== dependencies: "@types/node" "^20.1.0" - "@wdio/config" "8.34.0" + "@wdio/config" "8.36.1" "@wdio/logger" "8.28.0" "@wdio/protocols" "8.32.0" "@wdio/repl" "8.24.12" - "@wdio/types" "8.32.4" - "@wdio/utils" "8.33.1" + "@wdio/types" "8.36.1" + "@wdio/utils" "8.36.1" archiver "^7.0.0" aria-query "^5.0.0" css-shorthand-properties "^1.1.1" css-value "^0.0.1" - devtools-protocol "^0.0.1263784" + devtools-protocol "^0.0.1282316" grapheme-splitter "^1.0.2" import-meta-resolve "^4.0.0" is-plain-obj "^4.1.0" @@ -13145,7 +13263,7 @@ webdriverio@^8.34.1: resq "^1.9.1" rgb2hex "0.2.5" serialize-error "^11.0.1" - webdriver "8.34.0" + webdriver "8.36.1" webidl-conversions@^3.0.0: version "3.0.1" @@ -13545,6 +13663,17 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== +z-schema@~5.0.2: + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== + dependencies: + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" + optionalDependencies: + commander "^10.0.0" + zip-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79"